@earendil-works/chord 1.5.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1853) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +50 -90
  3. package/dist/contracts/accepts.d.ts +81 -0
  4. package/dist/contracts/accepts.d.ts.map +1 -0
  5. package/dist/contracts/accepts.js.map +1 -0
  6. package/dist/contracts/contract.d.ts +121 -0
  7. package/dist/contracts/contract.d.ts.map +1 -0
  8. package/dist/contracts/contract.js.map +1 -0
  9. package/dist/contracts/declare.d.ts.map +1 -0
  10. package/dist/contracts/declare.js.map +1 -0
  11. package/dist/contracts/evolve.d.ts.map +1 -0
  12. package/dist/contracts/evolve.js.map +1 -0
  13. package/dist/contracts/fingerprint.d.ts +16 -0
  14. package/dist/contracts/fingerprint.d.ts.map +1 -0
  15. package/dist/contracts/fingerprint.js.map +1 -0
  16. package/dist/contracts/history.d.ts.map +1 -0
  17. package/dist/contracts/history.js.map +1 -0
  18. package/dist/contracts/host-kind.d.ts.map +1 -0
  19. package/dist/contracts/host-kind.js.map +1 -0
  20. package/dist/contracts/index.d.ts.map +1 -0
  21. package/dist/contracts/index.js.map +1 -0
  22. package/dist/contracts/internal.d.ts.map +1 -0
  23. package/dist/contracts/internal.js.map +1 -0
  24. package/dist/contracts/names.d.ts.map +1 -0
  25. package/dist/contracts/names.js.map +1 -0
  26. package/dist/contracts/params.d.ts +28 -0
  27. package/dist/contracts/params.d.ts.map +1 -0
  28. package/dist/contracts/params.js.map +1 -0
  29. package/dist/contracts/schema.d.ts.map +1 -0
  30. package/dist/contracts/schema.js.map +1 -0
  31. package/dist/contracts/snapshot.d.ts +16 -0
  32. package/dist/contracts/snapshot.d.ts.map +1 -0
  33. package/dist/contracts/snapshot.js +167 -0
  34. package/dist/contracts/snapshot.js.map +1 -0
  35. package/dist/data/args.d.ts +50 -0
  36. package/dist/data/args.d.ts.map +1 -0
  37. package/dist/data/args.js.map +1 -0
  38. package/dist/data/errors.d.ts +80 -0
  39. package/dist/data/errors.d.ts.map +1 -0
  40. package/dist/data/errors.js +116 -0
  41. package/dist/data/errors.js.map +1 -0
  42. package/dist/data/failure.d.ts.map +1 -0
  43. package/dist/data/failure.js +77 -0
  44. package/dist/data/failure.js.map +1 -0
  45. package/dist/data/index.d.ts +4 -0
  46. package/dist/data/index.d.ts.map +1 -0
  47. package/dist/data/index.js +5 -0
  48. package/dist/data/index.js.map +1 -0
  49. package/dist/data/internal.d.ts +7 -0
  50. package/dist/data/internal.d.ts.map +1 -0
  51. package/dist/data/internal.js +8 -0
  52. package/dist/data/internal.js.map +1 -0
  53. package/dist/data/params.d.ts +20 -0
  54. package/dist/data/params.d.ts.map +1 -0
  55. package/dist/data/params.js.map +1 -0
  56. package/dist/data/principal.d.ts +22 -0
  57. package/dist/data/principal.d.ts.map +1 -0
  58. package/dist/data/principal.js +49 -0
  59. package/dist/data/principal.js.map +1 -0
  60. package/dist/data/validator.d.ts +12 -0
  61. package/dist/data/validator.d.ts.map +1 -0
  62. package/dist/data/validator.js +35 -0
  63. package/dist/data/validator.js.map +1 -0
  64. package/dist/documents/address-source.d.ts +20 -0
  65. package/dist/documents/address-source.d.ts.map +1 -0
  66. package/dist/documents/address-source.js.map +1 -0
  67. package/dist/documents/definition.d.ts +84 -0
  68. package/dist/documents/definition.d.ts.map +1 -0
  69. package/dist/documents/definition.js +74 -0
  70. package/dist/documents/definition.js.map +1 -0
  71. package/dist/documents/documents.d.ts +126 -0
  72. package/dist/documents/documents.d.ts.map +1 -0
  73. package/dist/documents/documents.js +248 -0
  74. package/dist/documents/documents.js.map +1 -0
  75. package/dist/documents/fence.d.ts.map +1 -0
  76. package/dist/documents/fence.js.map +1 -0
  77. package/dist/documents/handles.d.ts +76 -0
  78. package/dist/documents/handles.d.ts.map +1 -0
  79. package/dist/documents/handles.js.map +1 -0
  80. package/dist/documents/index.d.ts.map +1 -0
  81. package/dist/documents/index.js.map +1 -0
  82. package/dist/documents/internal.d.ts +9 -0
  83. package/dist/documents/internal.d.ts.map +1 -0
  84. package/dist/documents/internal.js.map +1 -0
  85. package/dist/documents/keyed-slot.d.ts +103 -0
  86. package/dist/documents/keyed-slot.d.ts.map +1 -0
  87. package/dist/documents/keyed-slot.js +395 -0
  88. package/dist/documents/keyed-slot.js.map +1 -0
  89. package/dist/documents/line.d.ts.map +1 -0
  90. package/dist/documents/line.js.map +1 -0
  91. package/dist/documents/persistence.d.ts +104 -0
  92. package/dist/documents/persistence.d.ts.map +1 -0
  93. package/dist/documents/persistence.js +129 -0
  94. package/dist/documents/persistence.js.map +1 -0
  95. package/dist/documents/residency.d.ts +31 -0
  96. package/dist/documents/residency.d.ts.map +1 -0
  97. package/dist/documents/residency.js.map +1 -0
  98. package/dist/documents/slot.d.ts +109 -0
  99. package/dist/documents/slot.d.ts.map +1 -0
  100. package/dist/documents/slot.js +181 -0
  101. package/dist/documents/slot.js.map +1 -0
  102. package/dist/documents/transaction.d.ts +143 -0
  103. package/dist/documents/transaction.d.ts.map +1 -0
  104. package/dist/documents/transaction.js +442 -0
  105. package/dist/documents/transaction.js.map +1 -0
  106. package/dist/host/activity.d.ts +31 -0
  107. package/dist/host/activity.d.ts.map +1 -0
  108. package/dist/host/activity.js +40 -0
  109. package/dist/host/activity.js.map +1 -0
  110. package/dist/host/adapted.d.ts +49 -0
  111. package/dist/host/adapted.d.ts.map +1 -0
  112. package/dist/host/adapted.js.map +1 -0
  113. package/dist/host/attempt.d.ts +308 -0
  114. package/dist/host/attempt.d.ts.map +1 -0
  115. package/dist/host/attempt.js +1199 -0
  116. package/dist/host/attempt.js.map +1 -0
  117. package/dist/host/backoff.d.ts.map +1 -0
  118. package/dist/host/backoff.js.map +1 -0
  119. package/dist/host/ctx.d.ts +94 -0
  120. package/dist/host/ctx.d.ts.map +1 -0
  121. package/dist/host/ctx.js +200 -0
  122. package/dist/host/ctx.js.map +1 -0
  123. package/dist/host/deadline.d.ts.map +1 -0
  124. package/dist/host/deadline.js.map +1 -0
  125. package/dist/host/dependencies.d.ts.map +1 -0
  126. package/dist/host/dependencies.js.map +1 -0
  127. package/dist/host/destination.d.ts +48 -0
  128. package/dist/host/destination.d.ts.map +1 -0
  129. package/dist/host/destination.js.map +1 -0
  130. package/dist/host/facet.d.ts +84 -0
  131. package/dist/host/facet.d.ts.map +1 -0
  132. package/dist/host/facet.js.map +1 -0
  133. package/dist/host/follow.d.ts +52 -0
  134. package/dist/host/follow.d.ts.map +1 -0
  135. package/dist/host/follow.js.map +1 -0
  136. package/dist/host/host.d.ts +571 -0
  137. package/dist/host/host.d.ts.map +1 -0
  138. package/dist/host/host.js +1318 -0
  139. package/dist/host/host.js.map +1 -0
  140. package/dist/host/index.d.ts +17 -0
  141. package/dist/host/index.d.ts.map +1 -0
  142. package/dist/host/index.js.map +1 -0
  143. package/dist/host/internal.d.ts +11 -0
  144. package/dist/host/internal.d.ts.map +1 -0
  145. package/dist/host/internal.js +9 -0
  146. package/dist/host/internal.js.map +1 -0
  147. package/dist/host/members.d.ts +50 -0
  148. package/dist/host/members.d.ts.map +1 -0
  149. package/dist/host/members.js.map +1 -0
  150. package/dist/host/native.d.ts +64 -0
  151. package/dist/host/native.d.ts.map +1 -0
  152. package/dist/host/native.js +126 -0
  153. package/dist/host/native.js.map +1 -0
  154. package/dist/host/object.d.ts +331 -0
  155. package/dist/host/object.d.ts.map +1 -0
  156. package/dist/host/object.js +1296 -0
  157. package/dist/host/object.js.map +1 -0
  158. package/dist/host/old-work.d.ts +34 -0
  159. package/dist/host/old-work.d.ts.map +1 -0
  160. package/dist/host/old-work.js +52 -0
  161. package/dist/host/old-work.js.map +1 -0
  162. package/dist/host/parked.d.ts +23 -0
  163. package/dist/host/parked.d.ts.map +1 -0
  164. package/dist/host/parked.js.map +1 -0
  165. package/dist/host/presence.d.ts +34 -0
  166. package/dist/host/presence.d.ts.map +1 -0
  167. package/dist/host/presence.js.map +1 -0
  168. package/dist/host/readiness.d.ts +27 -0
  169. package/dist/host/readiness.d.ts.map +1 -0
  170. package/dist/host/readiness.js +134 -0
  171. package/dist/host/readiness.js.map +1 -0
  172. package/dist/host/ref-state.d.ts +53 -0
  173. package/dist/host/ref-state.d.ts.map +1 -0
  174. package/dist/host/ref-state.js +83 -0
  175. package/dist/host/ref-state.js.map +1 -0
  176. package/dist/host/reference-keys.d.ts +36 -0
  177. package/dist/host/reference-keys.d.ts.map +1 -0
  178. package/dist/host/reference-keys.js +168 -0
  179. package/dist/host/reference-keys.js.map +1 -0
  180. package/dist/host/reference-source.d.ts +65 -0
  181. package/dist/host/reference-source.d.ts.map +1 -0
  182. package/dist/host/reference-source.js +285 -0
  183. package/dist/host/reference-source.js.map +1 -0
  184. package/dist/host/reference.d.ts +321 -0
  185. package/dist/host/reference.d.ts.map +1 -0
  186. package/dist/host/reference.js +797 -0
  187. package/dist/host/reference.js.map +1 -0
  188. package/dist/host/reload-cycle.d.ts +16 -0
  189. package/dist/host/reload-cycle.d.ts.map +1 -0
  190. package/dist/host/reload-cycle.js +81 -0
  191. package/dist/host/reload-cycle.js.map +1 -0
  192. package/dist/host/retry-on.d.ts.map +1 -0
  193. package/dist/host/retry-on.js.map +1 -0
  194. package/dist/host/revocation.d.ts +16 -0
  195. package/dist/host/revocation.d.ts.map +1 -0
  196. package/dist/host/revocation.js.map +1 -0
  197. package/dist/host/root.d.ts +37 -0
  198. package/dist/host/root.d.ts.map +1 -0
  199. package/dist/host/root.js +68 -0
  200. package/dist/host/root.js.map +1 -0
  201. package/dist/host/route.d.ts +64 -0
  202. package/dist/host/route.d.ts.map +1 -0
  203. package/dist/host/route.js +227 -0
  204. package/dist/host/route.js.map +1 -0
  205. package/dist/host/routines.d.ts +78 -0
  206. package/dist/host/routines.d.ts.map +1 -0
  207. package/dist/host/routines.js +398 -0
  208. package/dist/host/routines.js.map +1 -0
  209. package/dist/host/sleep.d.ts +9 -0
  210. package/dist/host/sleep.d.ts.map +1 -0
  211. package/dist/host/sleep.js.map +1 -0
  212. package/dist/host/staging.d.ts +94 -0
  213. package/dist/host/staging.d.ts.map +1 -0
  214. package/dist/host/staging.js +304 -0
  215. package/dist/host/staging.js.map +1 -0
  216. package/dist/host/unbound-clock.d.ts +23 -0
  217. package/dist/host/unbound-clock.d.ts.map +1 -0
  218. package/dist/host/unbound-clock.js +58 -0
  219. package/dist/host/unbound-clock.js.map +1 -0
  220. package/dist/host/unbound.d.ts +37 -0
  221. package/dist/host/unbound.d.ts.map +1 -0
  222. package/dist/host/unbound.js +88 -0
  223. package/dist/host/unbound.js.map +1 -0
  224. package/dist/host/uuid.d.ts.map +1 -0
  225. package/dist/host/uuid.js.map +1 -0
  226. package/dist/index.d.ts +29 -19
  227. package/dist/index.d.ts.map +1 -1
  228. package/dist/index.js +20 -10
  229. package/dist/index.js.map +1 -1
  230. package/dist/jobs/definition.d.ts.map +1 -0
  231. package/dist/jobs/definition.js.map +1 -0
  232. package/dist/jobs/index.d.ts.map +1 -0
  233. package/dist/jobs/index.js.map +1 -0
  234. package/dist/jobs/internal.d.ts.map +1 -0
  235. package/dist/jobs/internal.js.map +1 -0
  236. package/dist/jobs/job.d.ts +149 -0
  237. package/dist/jobs/job.d.ts.map +1 -0
  238. package/dist/jobs/job.js +387 -0
  239. package/dist/jobs/job.js.map +1 -0
  240. package/dist/jobs/persisted.d.ts +38 -0
  241. package/dist/jobs/persisted.d.ts.map +1 -0
  242. package/dist/jobs/persisted.js.map +1 -0
  243. package/dist/jobs/records.d.ts +231 -0
  244. package/dist/jobs/records.d.ts.map +1 -0
  245. package/dist/jobs/records.js +871 -0
  246. package/dist/jobs/records.js.map +1 -0
  247. package/dist/jobs/run-states.d.ts +69 -0
  248. package/dist/jobs/run-states.d.ts.map +1 -0
  249. package/dist/jobs/run-states.js +228 -0
  250. package/dist/jobs/run-states.js.map +1 -0
  251. package/dist/jobs/run.d.ts +117 -0
  252. package/dist/jobs/run.d.ts.map +1 -0
  253. package/dist/jobs/run.js +204 -0
  254. package/dist/jobs/run.js.map +1 -0
  255. package/dist/jobs/running.d.ts +44 -0
  256. package/dist/jobs/running.d.ts.map +1 -0
  257. package/dist/jobs/running.js.map +1 -0
  258. package/dist/jobs/stored.d.ts +63 -0
  259. package/dist/jobs/stored.d.ts.map +1 -0
  260. package/dist/jobs/stored.js.map +1 -0
  261. package/dist/link/binary.d.ts.map +1 -0
  262. package/dist/link/binary.js +544 -0
  263. package/dist/link/binary.js.map +1 -0
  264. package/dist/link/channel.d.ts +68 -0
  265. package/dist/link/channel.d.ts.map +1 -0
  266. package/dist/link/channel.js +215 -0
  267. package/dist/link/channel.js.map +1 -0
  268. package/dist/link/errors.d.ts.map +1 -0
  269. package/dist/link/errors.js.map +1 -0
  270. package/dist/link/index.d.ts.map +1 -0
  271. package/dist/link/index.js.map +1 -0
  272. package/dist/link/internal.d.ts.map +1 -0
  273. package/dist/link/internal.js.map +1 -0
  274. package/dist/link/ipc.d.ts.map +1 -0
  275. package/dist/link/ipc.js.map +1 -0
  276. package/dist/link/link.d.ts.map +1 -0
  277. package/dist/link/link.js.map +1 -0
  278. package/dist/link/message.d.ts +262 -0
  279. package/dist/link/message.d.ts.map +1 -0
  280. package/dist/link/message.js +156 -0
  281. package/dist/link/message.js.map +1 -0
  282. package/dist/link/part.d.ts +80 -0
  283. package/dist/link/part.d.ts.map +1 -0
  284. package/dist/link/part.js +165 -0
  285. package/dist/link/part.js.map +1 -0
  286. package/dist/link/text.d.ts.map +1 -0
  287. package/dist/link/text.js +355 -0
  288. package/dist/link/text.js.map +1 -0
  289. package/dist/link/values.d.ts.map +1 -0
  290. package/dist/link/values.js +121 -0
  291. package/dist/link/values.js.map +1 -0
  292. package/dist/link/websocket.d.ts.map +1 -0
  293. package/dist/link/websocket.js.map +1 -0
  294. package/dist/node/app/app.d.ts +269 -0
  295. package/dist/node/app/app.d.ts.map +1 -0
  296. package/dist/node/app/app.js +513 -0
  297. package/dist/node/app/app.js.map +1 -0
  298. package/dist/node/app/archive.d.ts +37 -0
  299. package/dist/node/app/archive.d.ts.map +1 -0
  300. package/dist/node/app/archive.js +204 -0
  301. package/dist/node/app/archive.js.map +1 -0
  302. package/dist/node/app/blobs.d.ts +23 -0
  303. package/dist/node/app/blobs.d.ts.map +1 -0
  304. package/dist/node/app/blobs.js +64 -0
  305. package/dist/node/app/blobs.js.map +1 -0
  306. package/dist/node/app/data.d.ts +35 -0
  307. package/dist/node/app/data.d.ts.map +1 -0
  308. package/dist/node/app/data.js +44 -0
  309. package/dist/node/app/data.js.map +1 -0
  310. package/dist/node/app/ephemeral-sessions.d.ts +20 -0
  311. package/dist/node/app/ephemeral-sessions.d.ts.map +1 -0
  312. package/dist/node/app/ephemeral-sessions.js +69 -0
  313. package/dist/node/app/ephemeral-sessions.js.map +1 -0
  314. package/dist/node/app/ephemeral.d.ts +11 -0
  315. package/dist/node/app/ephemeral.d.ts.map +1 -0
  316. package/dist/node/app/ephemeral.js +34 -0
  317. package/dist/node/app/ephemeral.js.map +1 -0
  318. package/dist/node/app/files-copy.d.ts +13 -0
  319. package/dist/node/app/files-copy.d.ts.map +1 -0
  320. package/dist/node/app/files-copy.js +86 -0
  321. package/dist/node/app/files-copy.js.map +1 -0
  322. package/dist/node/app/files-entry.d.ts +4 -0
  323. package/dist/node/app/files-entry.d.ts.map +1 -0
  324. package/dist/node/app/files-entry.js +7 -0
  325. package/dist/node/app/files-entry.js.map +1 -0
  326. package/dist/node/app/files-index.d.ts +180 -0
  327. package/dist/node/app/files-index.d.ts.map +1 -0
  328. package/dist/node/app/files-index.js +535 -0
  329. package/dist/node/app/files-index.js.map +1 -0
  330. package/dist/node/app/files.d.ts +363 -0
  331. package/dist/node/app/files.d.ts.map +1 -0
  332. package/dist/node/app/files.js +368 -0
  333. package/dist/node/app/files.js.map +1 -0
  334. package/dist/node/app/folder-views.d.ts +21 -0
  335. package/dist/node/app/folder-views.d.ts.map +1 -0
  336. package/dist/node/app/folder-views.js +55 -0
  337. package/dist/node/app/folder-views.js.map +1 -0
  338. package/dist/node/app/index.d.ts +12 -0
  339. package/dist/node/app/index.d.ts.map +1 -0
  340. package/dist/node/app/index.js +15 -0
  341. package/dist/node/app/index.js.map +1 -0
  342. package/dist/node/app/info.d.ts +66 -0
  343. package/dist/node/app/info.d.ts.map +1 -0
  344. package/dist/node/app/info.js +37 -0
  345. package/dist/node/app/info.js.map +1 -0
  346. package/dist/node/app/invite.d.ts +5 -0
  347. package/dist/node/app/invite.d.ts.map +1 -0
  348. package/dist/node/app/invite.js +64 -0
  349. package/dist/node/app/invite.js.map +1 -0
  350. package/dist/node/app/layout.d.ts +36 -0
  351. package/dist/node/app/layout.d.ts.map +1 -0
  352. package/dist/node/app/layout.js +87 -0
  353. package/dist/node/app/layout.js.map +1 -0
  354. package/dist/node/app/owner.d.ts +31 -0
  355. package/dist/node/app/owner.d.ts.map +1 -0
  356. package/dist/node/app/owner.js +104 -0
  357. package/dist/node/app/owner.js.map +1 -0
  358. package/dist/node/app/pairing.d.ts +55 -0
  359. package/dist/node/app/pairing.d.ts.map +1 -0
  360. package/dist/node/app/pairing.js +183 -0
  361. package/dist/node/app/pairing.js.map +1 -0
  362. package/dist/node/app/secrets.d.ts +16 -0
  363. package/dist/node/app/secrets.d.ts.map +1 -0
  364. package/dist/node/app/secrets.js +72 -0
  365. package/dist/node/app/secrets.js.map +1 -0
  366. package/dist/node/app/sessions.d.ts +72 -0
  367. package/dist/node/app/sessions.d.ts.map +1 -0
  368. package/dist/node/app/sessions.js +222 -0
  369. package/dist/node/app/sessions.js.map +1 -0
  370. package/dist/node/app/tar.d.ts +24 -0
  371. package/dist/node/app/tar.d.ts.map +1 -0
  372. package/dist/node/app/tar.js +167 -0
  373. package/dist/node/app/tar.js.map +1 -0
  374. package/dist/node/app/uploads.d.ts +37 -0
  375. package/dist/node/app/uploads.d.ts.map +1 -0
  376. package/dist/node/app/uploads.js +157 -0
  377. package/dist/node/app/uploads.js.map +1 -0
  378. package/dist/node/app/users.d.ts +37 -0
  379. package/dist/node/app/users.d.ts.map +1 -0
  380. package/dist/node/app/users.js +62 -0
  381. package/dist/node/app/users.js.map +1 -0
  382. package/dist/node/app/worker.d.ts +18 -0
  383. package/dist/node/app/worker.d.ts.map +1 -0
  384. package/dist/node/app/worker.js +84 -0
  385. package/dist/node/app/worker.js.map +1 -0
  386. package/dist/node/compression.d.ts +7 -0
  387. package/dist/node/compression.d.ts.map +1 -0
  388. package/dist/node/compression.js +25 -0
  389. package/dist/node/compression.js.map +1 -0
  390. package/dist/node/http/admission.d.ts.map +1 -0
  391. package/dist/node/http/admission.js.map +1 -0
  392. package/dist/node/http/authenticate.d.ts +21 -0
  393. package/dist/node/http/authenticate.d.ts.map +1 -0
  394. package/dist/node/http/authenticate.js +34 -0
  395. package/dist/node/http/authenticate.js.map +1 -0
  396. package/dist/node/http/cookies.d.ts +32 -0
  397. package/dist/node/http/cookies.d.ts.map +1 -0
  398. package/dist/node/http/cookies.js +70 -0
  399. package/dist/node/http/cookies.js.map +1 -0
  400. package/dist/node/http/file.d.ts.map +1 -0
  401. package/dist/node/http/file.js.map +1 -0
  402. package/dist/node/http/headers.d.ts.map +1 -0
  403. package/dist/node/http/headers.js +136 -0
  404. package/dist/node/http/headers.js.map +1 -0
  405. package/dist/node/http/http.d.ts +111 -0
  406. package/dist/node/http/http.d.ts.map +1 -0
  407. package/dist/node/http/http.js +524 -0
  408. package/dist/node/http/http.js.map +1 -0
  409. package/dist/node/http/incoming.d.ts.map +1 -0
  410. package/dist/node/http/incoming.js.map +1 -0
  411. package/dist/node/http/index.d.ts +11 -0
  412. package/dist/node/http/index.d.ts.map +1 -0
  413. package/dist/node/http/index.js +12 -0
  414. package/dist/node/http/index.js.map +1 -0
  415. package/dist/node/http/node.d.ts.map +1 -0
  416. package/dist/node/http/node.js.map +1 -0
  417. package/dist/node/http/request.d.ts +60 -0
  418. package/dist/node/http/request.d.ts.map +1 -0
  419. package/dist/node/http/request.js +118 -0
  420. package/dist/node/http/request.js.map +1 -0
  421. package/dist/node/http/response.d.ts +63 -0
  422. package/dist/node/http/response.d.ts.map +1 -0
  423. package/dist/node/http/response.js.map +1 -0
  424. package/dist/node/http/router.d.ts +132 -0
  425. package/dist/node/http/router.d.ts.map +1 -0
  426. package/dist/node/http/router.js +267 -0
  427. package/dist/node/http/router.js.map +1 -0
  428. package/dist/node/http/upgrades.d.ts +61 -0
  429. package/dist/node/http/upgrades.d.ts.map +1 -0
  430. package/dist/node/http/upgrades.js +192 -0
  431. package/dist/node/http/upgrades.js.map +1 -0
  432. package/dist/node/plugins/base-inputs.d.ts +14 -0
  433. package/dist/node/plugins/base-inputs.d.ts.map +1 -0
  434. package/dist/node/plugins/base-inputs.js +33 -0
  435. package/dist/node/plugins/base-inputs.js.map +1 -0
  436. package/dist/node/plugins/build.d.ts +77 -0
  437. package/dist/node/plugins/build.d.ts.map +1 -0
  438. package/dist/node/plugins/build.js +576 -0
  439. package/dist/node/plugins/build.js.map +1 -0
  440. package/dist/node/plugins/css-modules.d.ts +13 -0
  441. package/dist/node/plugins/css-modules.d.ts.map +1 -0
  442. package/dist/node/plugins/css-modules.js +58 -0
  443. package/dist/node/plugins/css-modules.js.map +1 -0
  444. package/dist/node/plugins/discover.d.ts +67 -0
  445. package/dist/node/plugins/discover.d.ts.map +1 -0
  446. package/dist/node/plugins/discover.js +369 -0
  447. package/dist/node/plugins/discover.js.map +1 -0
  448. package/dist/node/plugins/evaluate.d.ts +33 -0
  449. package/dist/node/plugins/evaluate.d.ts.map +1 -0
  450. package/dist/node/plugins/evaluate.js +121 -0
  451. package/dist/node/plugins/evaluate.js.map +1 -0
  452. package/dist/node/plugins/index.d.ts +11 -0
  453. package/dist/node/plugins/index.d.ts.map +1 -0
  454. package/dist/node/plugins/index.js +13 -0
  455. package/dist/node/plugins/index.js.map +1 -0
  456. package/dist/node/plugins/install.d.ts +38 -0
  457. package/dist/node/plugins/install.d.ts.map +1 -0
  458. package/dist/node/plugins/install.js +213 -0
  459. package/dist/node/plugins/install.js.map +1 -0
  460. package/dist/node/plugins/plugins.d.ts +162 -0
  461. package/dist/node/plugins/plugins.d.ts.map +1 -0
  462. package/dist/node/plugins/plugins.js +244 -0
  463. package/dist/node/plugins/plugins.js.map +1 -0
  464. package/dist/node/plugins/runtime.d.ts +57 -0
  465. package/dist/node/plugins/runtime.d.ts.map +1 -0
  466. package/dist/node/plugins/runtime.js +92 -0
  467. package/dist/node/plugins/runtime.js.map +1 -0
  468. package/dist/node/plugins/stack.d.ts.map +1 -0
  469. package/dist/node/plugins/stack.js.map +1 -0
  470. package/dist/node/plugins/testing.d.ts +58 -0
  471. package/dist/node/plugins/testing.d.ts.map +1 -0
  472. package/dist/node/plugins/testing.js +210 -0
  473. package/dist/node/plugins/testing.js.map +1 -0
  474. package/dist/node/plugins/watcher.d.ts +69 -0
  475. package/dist/node/plugins/watcher.d.ts.map +1 -0
  476. package/dist/node/plugins/watcher.js +622 -0
  477. package/dist/node/plugins/watcher.js.map +1 -0
  478. package/dist/node/surfaces/bundle.d.ts +31 -0
  479. package/dist/node/surfaces/bundle.d.ts.map +1 -0
  480. package/dist/node/surfaces/bundle.js +118 -0
  481. package/dist/node/surfaces/bundle.js.map +1 -0
  482. package/dist/node/surfaces/current.d.ts +17 -0
  483. package/dist/node/surfaces/current.d.ts.map +1 -0
  484. package/dist/node/surfaces/current.js +54 -0
  485. package/dist/node/surfaces/current.js.map +1 -0
  486. package/dist/node/surfaces/index.d.ts +6 -0
  487. package/dist/node/surfaces/index.d.ts.map +1 -0
  488. package/dist/node/surfaces/index.js +6 -0
  489. package/dist/node/surfaces/index.js.map +1 -0
  490. package/dist/node/surfaces/published.d.ts +27 -0
  491. package/dist/node/surfaces/published.d.ts.map +1 -0
  492. package/dist/node/surfaces/published.js +142 -0
  493. package/dist/node/surfaces/published.js.map +1 -0
  494. package/dist/node/surfaces/served.d.ts +15 -0
  495. package/dist/node/surfaces/served.d.ts.map +1 -0
  496. package/dist/node/surfaces/served.js +42 -0
  497. package/dist/node/surfaces/served.js.map +1 -0
  498. package/dist/node/surfaces/surface-build.d.ts +53 -0
  499. package/dist/node/surfaces/surface-build.d.ts.map +1 -0
  500. package/dist/node/surfaces/surface-build.js +105 -0
  501. package/dist/node/surfaces/surface-build.js.map +1 -0
  502. package/dist/node/surfaces/tui.d.ts +40 -0
  503. package/dist/node/surfaces/tui.d.ts.map +1 -0
  504. package/dist/node/surfaces/tui.js +55 -0
  505. package/dist/node/surfaces/tui.js.map +1 -0
  506. package/dist/node/surfaces/web.d.ts +56 -0
  507. package/dist/node/surfaces/web.d.ts.map +1 -0
  508. package/dist/node/surfaces/web.js +108 -0
  509. package/dist/node/surfaces/web.js.map +1 -0
  510. package/dist/node/tui/actions.d.ts +49 -0
  511. package/dist/node/tui/actions.d.ts.map +1 -0
  512. package/dist/node/tui/actions.js +195 -0
  513. package/dist/node/tui/actions.js.map +1 -0
  514. package/dist/node/tui/credentials.d.ts +17 -0
  515. package/dist/node/tui/credentials.d.ts.map +1 -0
  516. package/dist/node/tui/credentials.js +54 -0
  517. package/dist/node/tui/credentials.js.map +1 -0
  518. package/dist/node/tui/filter.d.ts +5 -0
  519. package/dist/node/tui/filter.d.ts.map +1 -0
  520. package/dist/node/tui/filter.js +79 -0
  521. package/dist/node/tui/filter.js.map +1 -0
  522. package/dist/node/tui/index.d.ts +6 -0
  523. package/dist/node/tui/index.d.ts.map +1 -0
  524. package/dist/node/tui/index.js +6 -0
  525. package/dist/node/tui/index.js.map +1 -0
  526. package/dist/node/tui/launcher.d.ts +40 -0
  527. package/dist/node/tui/launcher.d.ts.map +1 -0
  528. package/dist/node/tui/launcher.js +439 -0
  529. package/dist/node/tui/launcher.js.map +1 -0
  530. package/dist/node/tui/pipe.d.ts +18 -0
  531. package/dist/node/tui/pipe.d.ts.map +1 -0
  532. package/dist/node/tui/pipe.js +134 -0
  533. package/dist/node/tui/pipe.js.map +1 -0
  534. package/dist/node/tui/sandbox.d.ts +54 -0
  535. package/dist/node/tui/sandbox.d.ts.map +1 -0
  536. package/dist/node/tui/sandbox.js +431 -0
  537. package/dist/node/tui/sandbox.js.map +1 -0
  538. package/dist/node/workers/base.d.ts +30 -0
  539. package/dist/node/workers/base.d.ts.map +1 -0
  540. package/dist/node/workers/base.js +255 -0
  541. package/dist/node/workers/base.js.map +1 -0
  542. package/dist/node/workers/child.d.ts +4 -0
  543. package/dist/node/workers/child.d.ts.map +1 -0
  544. package/dist/node/workers/child.js +6 -0
  545. package/dist/node/workers/child.js.map +1 -0
  546. package/dist/node/workers/control.d.ts +83 -0
  547. package/dist/node/workers/control.d.ts.map +1 -0
  548. package/dist/node/workers/control.js +77 -0
  549. package/dist/node/workers/control.js.map +1 -0
  550. package/dist/node/workers/index.d.ts +4 -0
  551. package/dist/node/workers/index.d.ts.map +1 -0
  552. package/dist/node/workers/index.js +7 -0
  553. package/dist/node/workers/index.js.map +1 -0
  554. package/dist/node/workers/lock.d.ts +30 -0
  555. package/dist/node/workers/lock.d.ts.map +1 -0
  556. package/dist/node/workers/lock.js +180 -0
  557. package/dist/node/workers/lock.js.map +1 -0
  558. package/dist/node/workers/main.d.ts +46 -0
  559. package/dist/node/workers/main.d.ts.map +1 -0
  560. package/dist/node/workers/main.js +230 -0
  561. package/dist/node/workers/main.js.map +1 -0
  562. package/dist/node/workers/process.d.ts +42 -0
  563. package/dist/node/workers/process.d.ts.map +1 -0
  564. package/dist/node/workers/process.js +125 -0
  565. package/dist/node/workers/process.js.map +1 -0
  566. package/dist/node/workers/workers.d.ts +122 -0
  567. package/dist/node/workers/workers.d.ts.map +1 -0
  568. package/dist/node/workers/workers.js +677 -0
  569. package/dist/node/workers/workers.js.map +1 -0
  570. package/dist/react/hooks.d.ts +43 -0
  571. package/dist/react/hooks.d.ts.map +1 -0
  572. package/dist/react/hooks.js +82 -0
  573. package/dist/react/hooks.js.map +1 -0
  574. package/dist/react/index.d.ts +3 -0
  575. package/dist/react/index.d.ts.map +1 -0
  576. package/dist/react/index.js +4 -0
  577. package/dist/react/index.js.map +1 -0
  578. package/dist/react/stores.d.ts +9 -0
  579. package/dist/react/stores.d.ts.map +1 -0
  580. package/dist/react/stores.js +37 -0
  581. package/dist/react/stores.js.map +1 -0
  582. package/dist/registries/contribution.d.ts.map +1 -0
  583. package/dist/registries/contribution.js.map +1 -0
  584. package/dist/registries/entries.d.ts.map +1 -0
  585. package/dist/registries/entries.js.map +1 -0
  586. package/dist/registries/index.d.ts.map +1 -0
  587. package/dist/registries/index.js.map +1 -0
  588. package/dist/registries/internal.d.ts.map +1 -0
  589. package/dist/registries/internal.js.map +1 -0
  590. package/dist/registries/record.d.ts +115 -0
  591. package/dist/registries/record.d.ts.map +1 -0
  592. package/dist/registries/record.js +283 -0
  593. package/dist/registries/record.js.map +1 -0
  594. package/dist/registries/registry.d.ts +74 -0
  595. package/dist/registries/registry.d.ts.map +1 -0
  596. package/dist/registries/registry.js.map +1 -0
  597. package/dist/registries/value.d.ts.map +1 -0
  598. package/dist/registries/value.js +224 -0
  599. package/dist/registries/value.js.map +1 -0
  600. package/dist/remote/calls.d.ts.map +1 -0
  601. package/dist/remote/calls.js.map +1 -0
  602. package/dist/remote/consumer.d.ts +43 -0
  603. package/dist/remote/consumer.d.ts.map +1 -0
  604. package/dist/remote/consumer.js +350 -0
  605. package/dist/remote/consumer.js.map +1 -0
  606. package/dist/remote/hold.d.ts +141 -0
  607. package/dist/remote/hold.d.ts.map +1 -0
  608. package/dist/remote/hold.js +579 -0
  609. package/dist/remote/hold.js.map +1 -0
  610. package/dist/remote/host-link.d.ts +77 -0
  611. package/dist/remote/host-link.d.ts.map +1 -0
  612. package/dist/remote/host-link.js +184 -0
  613. package/dist/remote/host-link.js.map +1 -0
  614. package/dist/remote/internal.d.ts.map +1 -0
  615. package/dist/remote/internal.js.map +1 -0
  616. package/dist/remote/path.d.ts.map +1 -0
  617. package/dist/remote/path.js.map +1 -0
  618. package/dist/remote/provider.d.ts +89 -0
  619. package/dist/remote/provider.d.ts.map +1 -0
  620. package/dist/remote/provider.js +597 -0
  621. package/dist/remote/provider.js.map +1 -0
  622. package/dist/remote/relay.d.ts +69 -0
  623. package/dist/remote/relay.d.ts.map +1 -0
  624. package/dist/remote/relay.js +219 -0
  625. package/dist/remote/relay.js.map +1 -0
  626. package/dist/remote/remote-object.d.ts +138 -0
  627. package/dist/remote/remote-object.d.ts.map +1 -0
  628. package/dist/remote/remote-object.js +492 -0
  629. package/dist/remote/remote-object.js.map +1 -0
  630. package/dist/remote/replica.d.ts +59 -0
  631. package/dist/remote/replica.d.ts.map +1 -0
  632. package/dist/remote/replica.js +125 -0
  633. package/dist/remote/replica.js.map +1 -0
  634. package/dist/sqlite/node.d.ts +9 -1
  635. package/dist/sqlite/node.d.ts.map +1 -1
  636. package/dist/sqlite/node.js +9 -3
  637. package/dist/sqlite/node.js.map +1 -1
  638. package/dist/state/batch.d.ts +64 -0
  639. package/dist/state/batch.d.ts.map +1 -0
  640. package/dist/state/batch.js +164 -0
  641. package/dist/state/batch.js.map +1 -0
  642. package/dist/state/derive.d.ts +52 -0
  643. package/dist/state/derive.d.ts.map +1 -0
  644. package/dist/state/derive.js +182 -0
  645. package/dist/state/derive.js.map +1 -0
  646. package/dist/state/index.d.ts +6 -0
  647. package/dist/state/index.d.ts.map +1 -0
  648. package/dist/state/index.js.map +1 -0
  649. package/dist/state/internal.d.ts.map +1 -0
  650. package/dist/state/internal.js.map +1 -0
  651. package/dist/state/native-source.d.ts +106 -0
  652. package/dist/state/native-source.d.ts.map +1 -0
  653. package/dist/state/native-source.js +240 -0
  654. package/dist/state/native-source.js.map +1 -0
  655. package/dist/state/watchable.d.ts +114 -0
  656. package/dist/state/watchable.d.ts.map +1 -0
  657. package/dist/state/watchable.js +156 -0
  658. package/dist/state/watchable.js.map +1 -0
  659. package/dist/state/writable.d.ts +32 -0
  660. package/dist/state/writable.d.ts.map +1 -0
  661. package/dist/state/writable.js.map +1 -0
  662. package/dist/store/adapter.d.ts +67 -0
  663. package/dist/store/adapter.d.ts.map +1 -0
  664. package/dist/store/adapter.js.map +1 -0
  665. package/dist/store/allocator.d.ts.map +1 -0
  666. package/dist/store/allocator.js.map +1 -0
  667. package/dist/store/applier.d.ts.map +1 -0
  668. package/dist/store/applier.js.map +1 -0
  669. package/dist/store/apply-batch.d.ts +12 -0
  670. package/dist/store/apply-batch.d.ts.map +1 -0
  671. package/dist/store/apply-batch.js.map +1 -0
  672. package/dist/store/archive.d.ts +32 -0
  673. package/dist/store/archive.d.ts.map +1 -0
  674. package/dist/store/archive.js +130 -0
  675. package/dist/store/archive.js.map +1 -0
  676. package/dist/store/backend.d.ts +10 -0
  677. package/dist/store/backend.d.ts.map +1 -0
  678. package/dist/store/backend.js.map +1 -0
  679. package/dist/store/catalog.d.ts +24 -0
  680. package/dist/store/catalog.d.ts.map +1 -0
  681. package/dist/store/catalog.js.map +1 -0
  682. package/dist/store/claims.d.ts.map +1 -0
  683. package/dist/store/claims.js.map +1 -0
  684. package/dist/store/columns.d.ts.map +1 -0
  685. package/dist/store/columns.js.map +1 -0
  686. package/dist/store/engine.d.ts +176 -0
  687. package/dist/store/engine.d.ts.map +1 -0
  688. package/dist/store/engine.js +283 -0
  689. package/dist/store/engine.js.map +1 -0
  690. package/dist/store/evaluate.d.ts +17 -0
  691. package/dist/store/evaluate.d.ts.map +1 -0
  692. package/dist/store/evaluate.js.map +1 -0
  693. package/dist/store/export.d.ts +17 -0
  694. package/dist/store/export.d.ts.map +1 -0
  695. package/dist/store/export.js +200 -0
  696. package/dist/store/export.js.map +1 -0
  697. package/dist/store/expression.d.ts +150 -0
  698. package/dist/store/expression.d.ts.map +1 -0
  699. package/dist/store/expression.js.map +1 -0
  700. package/dist/store/import.d.ts +10 -0
  701. package/dist/store/import.d.ts.map +1 -0
  702. package/dist/store/import.js +276 -0
  703. package/dist/store/import.js.map +1 -0
  704. package/dist/store/index.d.ts.map +1 -0
  705. package/dist/store/index.js.map +1 -0
  706. package/dist/store/json-column.d.ts +33 -0
  707. package/dist/store/json-column.d.ts.map +1 -0
  708. package/dist/store/json-column.js +62 -0
  709. package/dist/store/json-column.js.map +1 -0
  710. package/dist/store/jsonl.d.ts.map +1 -0
  711. package/dist/store/jsonl.js.map +1 -0
  712. package/dist/store/live-query.d.ts +108 -0
  713. package/dist/store/live-query.d.ts.map +1 -0
  714. package/dist/store/live-query.js +254 -0
  715. package/dist/store/live-query.js.map +1 -0
  716. package/dist/store/outbox.d.ts +26 -0
  717. package/dist/store/outbox.d.ts.map +1 -0
  718. package/dist/store/outbox.js.map +1 -0
  719. package/dist/store/query.d.ts +39 -0
  720. package/dist/store/query.d.ts.map +1 -0
  721. package/dist/store/query.js.map +1 -0
  722. package/dist/store/refusal.d.ts.map +1 -0
  723. package/dist/store/refusal.js.map +1 -0
  724. package/dist/store/rows.d.ts +80 -0
  725. package/dist/store/rows.d.ts.map +1 -0
  726. package/dist/store/rows.js.map +1 -0
  727. package/dist/store/schema.d.ts +25 -0
  728. package/dist/store/schema.d.ts.map +1 -0
  729. package/dist/store/schema.js +115 -0
  730. package/dist/store/schema.js.map +1 -0
  731. package/dist/store/sql.d.ts +73 -0
  732. package/dist/store/sql.d.ts.map +1 -0
  733. package/dist/store/sql.js.map +1 -0
  734. package/dist/store/step.d.ts +50 -0
  735. package/dist/store/step.d.ts.map +1 -0
  736. package/dist/store/step.js +52 -0
  737. package/dist/store/step.js.map +1 -0
  738. package/dist/store/store.d.ts +171 -0
  739. package/dist/store/store.d.ts.map +1 -0
  740. package/dist/store/store.js +818 -0
  741. package/dist/store/store.js.map +1 -0
  742. package/dist/store/table-changes.d.ts +29 -0
  743. package/dist/store/table-changes.d.ts.map +1 -0
  744. package/dist/store/table-changes.js.map +1 -0
  745. package/dist/store/table-evolve.d.ts.map +1 -0
  746. package/dist/store/table-evolve.js.map +1 -0
  747. package/dist/store/table-handle.d.ts +73 -0
  748. package/dist/store/table-handle.d.ts.map +1 -0
  749. package/dist/store/table-handle.js +101 -0
  750. package/dist/store/table-handle.js.map +1 -0
  751. package/dist/store/table-history.d.ts.map +1 -0
  752. package/dist/store/table-history.js.map +1 -0
  753. package/dist/store/table-migration.d.ts +16 -0
  754. package/dist/store/table-migration.d.ts.map +1 -0
  755. package/dist/store/table-migration.js +202 -0
  756. package/dist/store/table-migration.js.map +1 -0
  757. package/dist/store/table-writes.d.ts.map +1 -0
  758. package/dist/store/table-writes.js +170 -0
  759. package/dist/store/table-writes.js.map +1 -0
  760. package/dist/store/table.d.ts +80 -0
  761. package/dist/store/table.d.ts.map +1 -0
  762. package/dist/store/table.js.map +1 -0
  763. package/dist/store/text.d.ts.map +1 -0
  764. package/dist/store/text.js.map +1 -0
  765. package/dist/store/writes.d.ts.map +1 -0
  766. package/dist/store/writes.js.map +1 -0
  767. package/dist/surfaces/active-language.d.ts +20 -0
  768. package/dist/surfaces/active-language.d.ts.map +1 -0
  769. package/dist/surfaces/active-language.js +78 -0
  770. package/dist/surfaces/active-language.js.map +1 -0
  771. package/dist/surfaces/active-theme.d.ts +16 -0
  772. package/dist/surfaces/active-theme.d.ts.map +1 -0
  773. package/dist/surfaces/active-theme.js +47 -0
  774. package/dist/surfaces/active-theme.js.map +1 -0
  775. package/dist/surfaces/client.d.ts +96 -0
  776. package/dist/surfaces/client.d.ts.map +1 -0
  777. package/dist/surfaces/client.js +264 -0
  778. package/dist/surfaces/client.js.map +1 -0
  779. package/dist/surfaces/connection.d.ts +49 -0
  780. package/dist/surfaces/connection.d.ts.map +1 -0
  781. package/dist/surfaces/connection.js +142 -0
  782. package/dist/surfaces/connection.js.map +1 -0
  783. package/dist/surfaces/format.d.ts +5 -0
  784. package/dist/surfaces/format.d.ts.map +1 -0
  785. package/dist/surfaces/format.js +37 -0
  786. package/dist/surfaces/format.js.map +1 -0
  787. package/dist/surfaces/index.d.ts +15 -0
  788. package/dist/surfaces/index.d.ts.map +1 -0
  789. package/dist/surfaces/index.js +18 -0
  790. package/dist/surfaces/index.js.map +1 -0
  791. package/dist/surfaces/language.d.ts +53 -0
  792. package/dist/surfaces/language.d.ts.map +1 -0
  793. package/dist/surfaces/language.js +74 -0
  794. package/dist/surfaces/language.js.map +1 -0
  795. package/dist/surfaces/loaded.d.ts +42 -0
  796. package/dist/surfaces/loaded.d.ts.map +1 -0
  797. package/dist/surfaces/loaded.js +116 -0
  798. package/dist/surfaces/loaded.js.map +1 -0
  799. package/dist/surfaces/locale-choice.d.ts +25 -0
  800. package/dist/surfaces/locale-choice.d.ts.map +1 -0
  801. package/dist/surfaces/locale-choice.js +14 -0
  802. package/dist/surfaces/locale-choice.js.map +1 -0
  803. package/dist/surfaces/messages.d.ts +67 -0
  804. package/dist/surfaces/messages.d.ts.map +1 -0
  805. package/dist/surfaces/messages.js +112 -0
  806. package/dist/surfaces/messages.js.map +1 -0
  807. package/dist/surfaces/page-state.d.ts +14 -0
  808. package/dist/surfaces/page-state.d.ts.map +1 -0
  809. package/dist/surfaces/page-state.js +43 -0
  810. package/dist/surfaces/page-state.js.map +1 -0
  811. package/dist/surfaces/preference.d.ts +32 -0
  812. package/dist/surfaces/preference.d.ts.map +1 -0
  813. package/dist/surfaces/preference.js +72 -0
  814. package/dist/surfaces/preference.js.map +1 -0
  815. package/dist/surfaces/registered.d.ts +33 -0
  816. package/dist/surfaces/registered.d.ts.map +1 -0
  817. package/dist/surfaces/registered.js +51 -0
  818. package/dist/surfaces/registered.js.map +1 -0
  819. package/dist/surfaces/scripts.d.ts +84 -0
  820. package/dist/surfaces/scripts.d.ts.map +1 -0
  821. package/dist/surfaces/scripts.js +28 -0
  822. package/dist/surfaces/scripts.js.map +1 -0
  823. package/dist/surfaces/theme-choice.d.ts +31 -0
  824. package/dist/surfaces/theme-choice.d.ts.map +1 -0
  825. package/dist/surfaces/theme-choice.js +18 -0
  826. package/dist/surfaces/theme-choice.js.map +1 -0
  827. package/dist/surfaces/themes.d.ts +43 -0
  828. package/dist/surfaces/themes.d.ts.map +1 -0
  829. package/dist/surfaces/themes.js +110 -0
  830. package/dist/surfaces/themes.js.map +1 -0
  831. package/dist/surfaces/translations.d.ts +29 -0
  832. package/dist/surfaces/translations.d.ts.map +1 -0
  833. package/dist/surfaces/translations.js +57 -0
  834. package/dist/surfaces/translations.js.map +1 -0
  835. package/dist/sync/batch.d.ts +18 -0
  836. package/dist/sync/batch.d.ts.map +1 -0
  837. package/dist/sync/batch.js +125 -0
  838. package/dist/sync/batch.js.map +1 -0
  839. package/dist/sync/client.d.ts +166 -0
  840. package/dist/sync/client.d.ts.map +1 -0
  841. package/dist/sync/client.js +438 -0
  842. package/dist/sync/client.js.map +1 -0
  843. package/dist/sync/files.d.ts +46 -0
  844. package/dist/sync/files.d.ts.map +1 -0
  845. package/dist/sync/files.js +13 -0
  846. package/dist/sync/files.js.map +1 -0
  847. package/dist/sync/filesystem.d.ts +37 -0
  848. package/dist/sync/filesystem.d.ts.map +1 -0
  849. package/dist/sync/filesystem.js +185 -0
  850. package/dist/sync/filesystem.js.map +1 -0
  851. package/dist/sync/index.d.ts +8 -0
  852. package/dist/sync/index.d.ts.map +1 -0
  853. package/dist/sync/index.js +9 -0
  854. package/dist/sync/index.js.map +1 -0
  855. package/dist/sync/lines.d.ts +18 -0
  856. package/dist/sync/lines.d.ts.map +1 -0
  857. package/dist/sync/lines.js +46 -0
  858. package/dist/sync/lines.js.map +1 -0
  859. package/dist/sync/remote.d.ts +130 -0
  860. package/dist/sync/remote.d.ts.map +1 -0
  861. package/dist/sync/remote.js +46 -0
  862. package/dist/sync/remote.js.map +1 -0
  863. package/dist/sync/state.d.ts +17 -0
  864. package/dist/sync/state.d.ts.map +1 -0
  865. package/dist/sync/state.js +40 -0
  866. package/dist/sync/state.js.map +1 -0
  867. package/dist/telemetry-ingest/batch.d.ts +70 -0
  868. package/dist/telemetry-ingest/batch.d.ts.map +1 -0
  869. package/dist/telemetry-ingest/batch.js +110 -0
  870. package/dist/telemetry-ingest/batch.js.map +1 -0
  871. package/dist/telemetry-ingest/facet.d.ts +21 -0
  872. package/dist/telemetry-ingest/facet.d.ts.map +1 -0
  873. package/dist/telemetry-ingest/facet.js +96 -0
  874. package/dist/telemetry-ingest/facet.js.map +1 -0
  875. package/dist/telemetry-ingest/index.d.ts +5 -0
  876. package/dist/telemetry-ingest/index.d.ts.map +1 -0
  877. package/dist/telemetry-ingest/index.js +8 -0
  878. package/dist/telemetry-ingest/index.js.map +1 -0
  879. package/dist/telemetry-ingest/recorder.d.ts +50 -0
  880. package/dist/telemetry-ingest/recorder.d.ts.map +1 -0
  881. package/dist/telemetry-ingest/recorder.js +298 -0
  882. package/dist/telemetry-ingest/recorder.js.map +1 -0
  883. package/dist/telemetry-ingest/sender.d.ts +14 -0
  884. package/dist/telemetry-ingest/sender.d.ts.map +1 -0
  885. package/dist/telemetry-ingest/sender.js +64 -0
  886. package/dist/telemetry-ingest/sender.js.map +1 -0
  887. package/dist/telemetry-sqlite/index.d.ts +13 -4
  888. package/dist/telemetry-sqlite/index.d.ts.map +1 -1
  889. package/dist/telemetry-sqlite/index.js +81 -241
  890. package/dist/telemetry-sqlite/index.js.map +1 -1
  891. package/dist/telemetry-sqlite/node.d.ts +13 -0
  892. package/dist/telemetry-sqlite/node.d.ts.map +1 -0
  893. package/dist/telemetry-sqlite/node.js +27 -0
  894. package/dist/telemetry-sqlite/node.js.map +1 -0
  895. package/dist/telemetry-sqlite/schema.d.ts +9 -0
  896. package/dist/telemetry-sqlite/schema.d.ts.map +1 -0
  897. package/dist/telemetry-sqlite/schema.js +61 -0
  898. package/dist/telemetry-sqlite/schema.js.map +1 -0
  899. package/dist/telemetry-sqlite/store.d.ts +3 -0
  900. package/dist/telemetry-sqlite/store.d.ts.map +1 -1
  901. package/dist/telemetry-sqlite/store.js +24 -13
  902. package/dist/telemetry-sqlite/store.js.map +1 -1
  903. package/dist/telemetry.d.ts +937 -0
  904. package/dist/telemetry.d.ts.map +1 -0
  905. package/dist/telemetry.js +470 -0
  906. package/dist/telemetry.js.map +1 -0
  907. package/dist/tui/bridge.d.ts +112 -0
  908. package/dist/tui/bridge.d.ts.map +1 -0
  909. package/dist/tui/bridge.js +9 -0
  910. package/dist/tui/bridge.js.map +1 -0
  911. package/dist/tui/channel.d.ts +44 -0
  912. package/dist/tui/channel.d.ts.map +1 -0
  913. package/dist/tui/channel.js +150 -0
  914. package/dist/tui/channel.js.map +1 -0
  915. package/dist/tui/frames.d.ts +5 -0
  916. package/dist/tui/frames.d.ts.map +1 -0
  917. package/dist/tui/frames.js +52 -0
  918. package/dist/tui/frames.js.map +1 -0
  919. package/dist/tui/index.d.ts +7 -0
  920. package/dist/tui/index.d.ts.map +1 -0
  921. package/dist/tui/index.js +8 -0
  922. package/dist/tui/index.js.map +1 -0
  923. package/dist/tui/runtime.d.ts +46 -0
  924. package/dist/tui/runtime.d.ts.map +1 -0
  925. package/dist/tui/runtime.js +101 -0
  926. package/dist/tui/runtime.js.map +1 -0
  927. package/dist/tui/scope.d.ts +46 -0
  928. package/dist/tui/scope.d.ts.map +1 -0
  929. package/dist/tui/scope.js +141 -0
  930. package/dist/tui/scope.js.map +1 -0
  931. package/dist/tui/terminal.d.ts +15 -0
  932. package/dist/tui/terminal.d.ts.map +1 -0
  933. package/dist/tui/terminal.js +37 -0
  934. package/dist/tui/terminal.js.map +1 -0
  935. package/dist/tui/theme.d.ts +17 -0
  936. package/dist/tui/theme.d.ts.map +1 -0
  937. package/dist/tui/theme.js +38 -0
  938. package/dist/tui/theme.js.map +1 -0
  939. package/dist/web/environment.d.ts +4 -0
  940. package/dist/web/environment.d.ts.map +1 -0
  941. package/dist/web/environment.js +37 -0
  942. package/dist/web/environment.js.map +1 -0
  943. package/dist/web/index.d.ts +5 -0
  944. package/dist/web/index.d.ts.map +1 -0
  945. package/dist/web/index.js +7 -0
  946. package/dist/web/index.js.map +1 -0
  947. package/dist/web/language.d.ts +7 -0
  948. package/dist/web/language.d.ts.map +1 -0
  949. package/dist/web/language.js +21 -0
  950. package/dist/web/language.js.map +1 -0
  951. package/dist/web/page.d.ts +29 -0
  952. package/dist/web/page.d.ts.map +1 -0
  953. package/dist/web/page.js +92 -0
  954. package/dist/web/page.js.map +1 -0
  955. package/dist/web/scripts.d.ts +23 -0
  956. package/dist/web/scripts.d.ts.map +1 -0
  957. package/dist/web/scripts.js +50 -0
  958. package/dist/web/scripts.js.map +1 -0
  959. package/dist/web/styles.d.ts +17 -0
  960. package/dist/web/styles.d.ts.map +1 -0
  961. package/dist/web/styles.js +218 -0
  962. package/dist/web/styles.js.map +1 -0
  963. package/dist/web/themes.d.ts +6 -0
  964. package/dist/web/themes.d.ts.map +1 -0
  965. package/dist/web/themes.js +31 -0
  966. package/dist/web/themes.js.map +1 -0
  967. package/docs/benchmarks.md +1036 -0
  968. package/docs/decisions.md +3436 -0
  969. package/docs/dependencies/book.md +1671 -0
  970. package/docs/dependencies/index.html +2641 -0
  971. package/docs/design.md +3065 -0
  972. package/docs/durable-observers/book.md +432 -0
  973. package/docs/durable-observers/index.html +517 -0
  974. package/docs/guide-plugins-hosts/book.md +957 -0
  975. package/docs/guide-plugins-hosts/index.html +952 -0
  976. package/docs/http-workers/book.md +378 -0
  977. package/docs/http-workers/index.html +515 -0
  978. package/docs/i18n/book.md +217 -0
  979. package/docs/i18n/index.html +344 -0
  980. package/docs/layer-1.md +311 -0
  981. package/docs/layer-2.md +216 -0
  982. package/docs/p3-features/README.md +6 -0
  983. package/docs/p3-features/book.md +478 -0
  984. package/docs/plugin-authoring.md +276 -0
  985. package/docs/plugin-model/book.md +186 -0
  986. package/docs/plugin-model/index.html +310 -0
  987. package/docs/plugin-primer/book.md +273 -0
  988. package/docs/plugin-primer/index.html +430 -0
  989. package/docs/slice-1.md +236 -0
  990. package/docs/slice-10.md +288 -0
  991. package/docs/slice-11.md +114 -0
  992. package/docs/slice-12.md +132 -0
  993. package/docs/slice-13.md +121 -0
  994. package/docs/slice-2.md +174 -0
  995. package/docs/slice-3a.md +296 -0
  996. package/docs/slice-3b.md +197 -0
  997. package/docs/slice-4a.md +418 -0
  998. package/docs/slice-4b.md +208 -0
  999. package/docs/slice-6a.md +676 -0
  1000. package/docs/slice-6b.md +332 -0
  1001. package/docs/slice-7b/book.md +608 -0
  1002. package/docs/slice-7b/index.html +842 -0
  1003. package/docs/slice-7b.md +255 -0
  1004. package/docs/slice-7c.md +165 -0
  1005. package/docs/slice-9.md +110 -0
  1006. package/docs/slices.md +241 -0
  1007. package/docs/store/book.md +670 -0
  1008. package/docs/store/index.html +861 -0
  1009. package/docs/store/walkthrough.md +193 -0
  1010. package/docs/theming/book.md +223 -0
  1011. package/docs/theming/index.html +371 -0
  1012. package/docs/tutorial/book.md +2169 -0
  1013. package/docs/tutorial/index.html +2112 -0
  1014. package/docs/tutorial/screens/click-after.png +0 -0
  1015. package/docs/tutorial/screens/click-before.png +0 -0
  1016. package/docs/tutorial/screens/edited.png +0 -0
  1017. package/docs/tutorial/screens/french.png +0 -0
  1018. package/docs/tutorial/screens/harbor.png +0 -0
  1019. package/docs/tutorial/screens/page.png +0 -0
  1020. package/docs/tutorial/screens/traces-ada.png +0 -0
  1021. package/docs/tutorial/screens/traces.png +0 -0
  1022. package/package.json +99 -21
  1023. package/dist/cell.d.ts +0 -122
  1024. package/dist/cell.d.ts.map +0 -1
  1025. package/dist/cell.js +0 -356
  1026. package/dist/cell.js.map +0 -1
  1027. package/dist/cluster.d.ts +0 -27
  1028. package/dist/cluster.d.ts.map +0 -1
  1029. package/dist/cluster.js +0 -230
  1030. package/dist/cluster.js.map +0 -1
  1031. package/dist/connection.d.ts +0 -270
  1032. package/dist/connection.d.ts.map +0 -1
  1033. package/dist/connection.js +0 -1216
  1034. package/dist/connection.js.map +0 -1
  1035. package/dist/contract.d.ts +0 -207
  1036. package/dist/contract.d.ts.map +0 -1
  1037. package/dist/contract.js +0 -241
  1038. package/dist/contract.js.map +0 -1
  1039. package/dist/declare.d.ts +0 -33
  1040. package/dist/declare.d.ts.map +0 -1
  1041. package/dist/declare.js +0 -2
  1042. package/dist/declare.js.map +0 -1
  1043. package/dist/errors.d.ts +0 -28
  1044. package/dist/errors.d.ts.map +0 -1
  1045. package/dist/errors.js +0 -59
  1046. package/dist/errors.js.map +0 -1
  1047. package/dist/host.d.ts +0 -348
  1048. package/dist/host.d.ts.map +0 -1
  1049. package/dist/host.js +0 -1002
  1050. package/dist/host.js.map +0 -1
  1051. package/dist/link.d.ts +0 -107
  1052. package/dist/link.d.ts.map +0 -1
  1053. package/dist/link.js +0 -355
  1054. package/dist/link.js.map +0 -1
  1055. package/dist/loader.d.ts +0 -4
  1056. package/dist/loader.d.ts.map +0 -1
  1057. package/dist/loader.js +0 -73
  1058. package/dist/loader.js.map +0 -1
  1059. package/dist/manager.d.ts +0 -115
  1060. package/dist/manager.d.ts.map +0 -1
  1061. package/dist/manager.js +0 -345
  1062. package/dist/manager.js.map +0 -1
  1063. package/dist/next/contracts/accepts.d.ts +0 -81
  1064. package/dist/next/contracts/accepts.d.ts.map +0 -1
  1065. package/dist/next/contracts/accepts.js.map +0 -1
  1066. package/dist/next/contracts/contract.d.ts +0 -121
  1067. package/dist/next/contracts/contract.d.ts.map +0 -1
  1068. package/dist/next/contracts/contract.js.map +0 -1
  1069. package/dist/next/contracts/declare.d.ts.map +0 -1
  1070. package/dist/next/contracts/declare.js.map +0 -1
  1071. package/dist/next/contracts/evolve.d.ts.map +0 -1
  1072. package/dist/next/contracts/evolve.js.map +0 -1
  1073. package/dist/next/contracts/fingerprint.d.ts +0 -16
  1074. package/dist/next/contracts/fingerprint.d.ts.map +0 -1
  1075. package/dist/next/contracts/fingerprint.js.map +0 -1
  1076. package/dist/next/contracts/history.d.ts.map +0 -1
  1077. package/dist/next/contracts/history.js.map +0 -1
  1078. package/dist/next/contracts/host-kind.d.ts.map +0 -1
  1079. package/dist/next/contracts/host-kind.js.map +0 -1
  1080. package/dist/next/contracts/index.d.ts.map +0 -1
  1081. package/dist/next/contracts/index.js.map +0 -1
  1082. package/dist/next/contracts/internal.d.ts.map +0 -1
  1083. package/dist/next/contracts/internal.js.map +0 -1
  1084. package/dist/next/contracts/names.d.ts.map +0 -1
  1085. package/dist/next/contracts/names.js.map +0 -1
  1086. package/dist/next/contracts/params.d.ts +0 -28
  1087. package/dist/next/contracts/params.d.ts.map +0 -1
  1088. package/dist/next/contracts/params.js.map +0 -1
  1089. package/dist/next/contracts/schema.d.ts.map +0 -1
  1090. package/dist/next/contracts/schema.js.map +0 -1
  1091. package/dist/next/contracts/snapshot.d.ts +0 -16
  1092. package/dist/next/contracts/snapshot.d.ts.map +0 -1
  1093. package/dist/next/contracts/snapshot.js +0 -167
  1094. package/dist/next/contracts/snapshot.js.map +0 -1
  1095. package/dist/next/data/args.d.ts +0 -50
  1096. package/dist/next/data/args.d.ts.map +0 -1
  1097. package/dist/next/data/args.js.map +0 -1
  1098. package/dist/next/data/errors.d.ts +0 -73
  1099. package/dist/next/data/errors.d.ts.map +0 -1
  1100. package/dist/next/data/errors.js +0 -107
  1101. package/dist/next/data/errors.js.map +0 -1
  1102. package/dist/next/data/failure.d.ts.map +0 -1
  1103. package/dist/next/data/failure.js +0 -72
  1104. package/dist/next/data/failure.js.map +0 -1
  1105. package/dist/next/data/index.d.ts +0 -4
  1106. package/dist/next/data/index.d.ts.map +0 -1
  1107. package/dist/next/data/index.js +0 -4
  1108. package/dist/next/data/index.js.map +0 -1
  1109. package/dist/next/data/internal.d.ts +0 -7
  1110. package/dist/next/data/internal.d.ts.map +0 -1
  1111. package/dist/next/data/internal.js +0 -8
  1112. package/dist/next/data/internal.js.map +0 -1
  1113. package/dist/next/data/params.d.ts +0 -20
  1114. package/dist/next/data/params.d.ts.map +0 -1
  1115. package/dist/next/data/params.js.map +0 -1
  1116. package/dist/next/data/principal.d.ts +0 -17
  1117. package/dist/next/data/principal.d.ts.map +0 -1
  1118. package/dist/next/data/principal.js +0 -41
  1119. package/dist/next/data/principal.js.map +0 -1
  1120. package/dist/next/data/validator.d.ts +0 -12
  1121. package/dist/next/data/validator.d.ts.map +0 -1
  1122. package/dist/next/data/validator.js +0 -34
  1123. package/dist/next/data/validator.js.map +0 -1
  1124. package/dist/next/documents/address-source.d.ts +0 -20
  1125. package/dist/next/documents/address-source.d.ts.map +0 -1
  1126. package/dist/next/documents/address-source.js.map +0 -1
  1127. package/dist/next/documents/definition.d.ts +0 -84
  1128. package/dist/next/documents/definition.d.ts.map +0 -1
  1129. package/dist/next/documents/definition.js +0 -73
  1130. package/dist/next/documents/definition.js.map +0 -1
  1131. package/dist/next/documents/documents.d.ts +0 -106
  1132. package/dist/next/documents/documents.d.ts.map +0 -1
  1133. package/dist/next/documents/documents.js +0 -224
  1134. package/dist/next/documents/documents.js.map +0 -1
  1135. package/dist/next/documents/fence.d.ts.map +0 -1
  1136. package/dist/next/documents/fence.js.map +0 -1
  1137. package/dist/next/documents/handles.d.ts +0 -76
  1138. package/dist/next/documents/handles.d.ts.map +0 -1
  1139. package/dist/next/documents/handles.js.map +0 -1
  1140. package/dist/next/documents/index.d.ts.map +0 -1
  1141. package/dist/next/documents/index.js.map +0 -1
  1142. package/dist/next/documents/internal.d.ts +0 -9
  1143. package/dist/next/documents/internal.d.ts.map +0 -1
  1144. package/dist/next/documents/internal.js.map +0 -1
  1145. package/dist/next/documents/keyed-slot.d.ts +0 -103
  1146. package/dist/next/documents/keyed-slot.d.ts.map +0 -1
  1147. package/dist/next/documents/keyed-slot.js +0 -395
  1148. package/dist/next/documents/keyed-slot.js.map +0 -1
  1149. package/dist/next/documents/line.d.ts.map +0 -1
  1150. package/dist/next/documents/line.js.map +0 -1
  1151. package/dist/next/documents/persistence.d.ts +0 -104
  1152. package/dist/next/documents/persistence.d.ts.map +0 -1
  1153. package/dist/next/documents/persistence.js +0 -128
  1154. package/dist/next/documents/persistence.js.map +0 -1
  1155. package/dist/next/documents/residency.d.ts +0 -31
  1156. package/dist/next/documents/residency.d.ts.map +0 -1
  1157. package/dist/next/documents/residency.js.map +0 -1
  1158. package/dist/next/documents/slot.d.ts +0 -109
  1159. package/dist/next/documents/slot.d.ts.map +0 -1
  1160. package/dist/next/documents/slot.js +0 -181
  1161. package/dist/next/documents/slot.js.map +0 -1
  1162. package/dist/next/documents/transaction.d.ts +0 -133
  1163. package/dist/next/documents/transaction.d.ts.map +0 -1
  1164. package/dist/next/documents/transaction.js +0 -409
  1165. package/dist/next/documents/transaction.js.map +0 -1
  1166. package/dist/next/host/activity.d.ts +0 -31
  1167. package/dist/next/host/activity.d.ts.map +0 -1
  1168. package/dist/next/host/activity.js +0 -40
  1169. package/dist/next/host/activity.js.map +0 -1
  1170. package/dist/next/host/adapted.d.ts +0 -49
  1171. package/dist/next/host/adapted.d.ts.map +0 -1
  1172. package/dist/next/host/adapted.js.map +0 -1
  1173. package/dist/next/host/attempt.d.ts +0 -278
  1174. package/dist/next/host/attempt.d.ts.map +0 -1
  1175. package/dist/next/host/attempt.js +0 -1072
  1176. package/dist/next/host/attempt.js.map +0 -1
  1177. package/dist/next/host/backoff.d.ts.map +0 -1
  1178. package/dist/next/host/backoff.js.map +0 -1
  1179. package/dist/next/host/ctx.d.ts +0 -47
  1180. package/dist/next/host/ctx.d.ts.map +0 -1
  1181. package/dist/next/host/ctx.js +0 -108
  1182. package/dist/next/host/ctx.js.map +0 -1
  1183. package/dist/next/host/deadline.d.ts.map +0 -1
  1184. package/dist/next/host/deadline.js.map +0 -1
  1185. package/dist/next/host/dependencies.d.ts.map +0 -1
  1186. package/dist/next/host/dependencies.js.map +0 -1
  1187. package/dist/next/host/destination.d.ts +0 -48
  1188. package/dist/next/host/destination.d.ts.map +0 -1
  1189. package/dist/next/host/destination.js.map +0 -1
  1190. package/dist/next/host/facet.d.ts +0 -79
  1191. package/dist/next/host/facet.d.ts.map +0 -1
  1192. package/dist/next/host/facet.js.map +0 -1
  1193. package/dist/next/host/follow.d.ts +0 -52
  1194. package/dist/next/host/follow.d.ts.map +0 -1
  1195. package/dist/next/host/follow.js.map +0 -1
  1196. package/dist/next/host/host.d.ts +0 -495
  1197. package/dist/next/host/host.d.ts.map +0 -1
  1198. package/dist/next/host/host.js +0 -1075
  1199. package/dist/next/host/host.js.map +0 -1
  1200. package/dist/next/host/index.d.ts +0 -17
  1201. package/dist/next/host/index.d.ts.map +0 -1
  1202. package/dist/next/host/index.js.map +0 -1
  1203. package/dist/next/host/internal.d.ts +0 -10
  1204. package/dist/next/host/internal.d.ts.map +0 -1
  1205. package/dist/next/host/internal.js +0 -8
  1206. package/dist/next/host/internal.js.map +0 -1
  1207. package/dist/next/host/members.d.ts +0 -50
  1208. package/dist/next/host/members.d.ts.map +0 -1
  1209. package/dist/next/host/members.js.map +0 -1
  1210. package/dist/next/host/native.d.ts +0 -55
  1211. package/dist/next/host/native.d.ts.map +0 -1
  1212. package/dist/next/host/native.js +0 -92
  1213. package/dist/next/host/native.js.map +0 -1
  1214. package/dist/next/host/object.d.ts +0 -290
  1215. package/dist/next/host/object.d.ts.map +0 -1
  1216. package/dist/next/host/object.js +0 -1127
  1217. package/dist/next/host/object.js.map +0 -1
  1218. package/dist/next/host/parked.d.ts +0 -23
  1219. package/dist/next/host/parked.d.ts.map +0 -1
  1220. package/dist/next/host/parked.js.map +0 -1
  1221. package/dist/next/host/presence.d.ts +0 -34
  1222. package/dist/next/host/presence.d.ts.map +0 -1
  1223. package/dist/next/host/presence.js.map +0 -1
  1224. package/dist/next/host/ref-state.d.ts +0 -53
  1225. package/dist/next/host/ref-state.d.ts.map +0 -1
  1226. package/dist/next/host/ref-state.js +0 -83
  1227. package/dist/next/host/ref-state.js.map +0 -1
  1228. package/dist/next/host/reference-keys.d.ts +0 -36
  1229. package/dist/next/host/reference-keys.d.ts.map +0 -1
  1230. package/dist/next/host/reference-keys.js +0 -168
  1231. package/dist/next/host/reference-keys.js.map +0 -1
  1232. package/dist/next/host/reference-source.d.ts +0 -65
  1233. package/dist/next/host/reference-source.d.ts.map +0 -1
  1234. package/dist/next/host/reference-source.js +0 -285
  1235. package/dist/next/host/reference-source.js.map +0 -1
  1236. package/dist/next/host/reference.d.ts +0 -308
  1237. package/dist/next/host/reference.d.ts.map +0 -1
  1238. package/dist/next/host/reference.js +0 -775
  1239. package/dist/next/host/reference.js.map +0 -1
  1240. package/dist/next/host/retry-on.d.ts.map +0 -1
  1241. package/dist/next/host/retry-on.js.map +0 -1
  1242. package/dist/next/host/revocation.d.ts +0 -16
  1243. package/dist/next/host/revocation.d.ts.map +0 -1
  1244. package/dist/next/host/revocation.js.map +0 -1
  1245. package/dist/next/host/root.d.ts +0 -27
  1246. package/dist/next/host/root.d.ts.map +0 -1
  1247. package/dist/next/host/root.js +0 -68
  1248. package/dist/next/host/root.js.map +0 -1
  1249. package/dist/next/host/route.d.ts +0 -64
  1250. package/dist/next/host/route.d.ts.map +0 -1
  1251. package/dist/next/host/route.js +0 -190
  1252. package/dist/next/host/route.js.map +0 -1
  1253. package/dist/next/host/routines.d.ts +0 -76
  1254. package/dist/next/host/routines.d.ts.map +0 -1
  1255. package/dist/next/host/routines.js +0 -350
  1256. package/dist/next/host/routines.js.map +0 -1
  1257. package/dist/next/host/sleep.d.ts +0 -9
  1258. package/dist/next/host/sleep.d.ts.map +0 -1
  1259. package/dist/next/host/sleep.js.map +0 -1
  1260. package/dist/next/host/staging.d.ts +0 -94
  1261. package/dist/next/host/staging.d.ts.map +0 -1
  1262. package/dist/next/host/staging.js +0 -302
  1263. package/dist/next/host/staging.js.map +0 -1
  1264. package/dist/next/host/unbound.d.ts +0 -30
  1265. package/dist/next/host/unbound.d.ts.map +0 -1
  1266. package/dist/next/host/unbound.js +0 -67
  1267. package/dist/next/host/unbound.js.map +0 -1
  1268. package/dist/next/host/uuid.d.ts.map +0 -1
  1269. package/dist/next/host/uuid.js.map +0 -1
  1270. package/dist/next/index.d.ts +0 -28
  1271. package/dist/next/index.d.ts.map +0 -1
  1272. package/dist/next/index.js +0 -18
  1273. package/dist/next/index.js.map +0 -1
  1274. package/dist/next/jobs/definition.d.ts.map +0 -1
  1275. package/dist/next/jobs/definition.js.map +0 -1
  1276. package/dist/next/jobs/index.d.ts.map +0 -1
  1277. package/dist/next/jobs/index.js.map +0 -1
  1278. package/dist/next/jobs/internal.d.ts.map +0 -1
  1279. package/dist/next/jobs/internal.js.map +0 -1
  1280. package/dist/next/jobs/job.d.ts +0 -152
  1281. package/dist/next/jobs/job.d.ts.map +0 -1
  1282. package/dist/next/jobs/job.js +0 -320
  1283. package/dist/next/jobs/job.js.map +0 -1
  1284. package/dist/next/jobs/persisted.d.ts +0 -38
  1285. package/dist/next/jobs/persisted.d.ts.map +0 -1
  1286. package/dist/next/jobs/persisted.js.map +0 -1
  1287. package/dist/next/jobs/records.d.ts +0 -231
  1288. package/dist/next/jobs/records.d.ts.map +0 -1
  1289. package/dist/next/jobs/records.js +0 -869
  1290. package/dist/next/jobs/records.js.map +0 -1
  1291. package/dist/next/jobs/run-states.d.ts +0 -69
  1292. package/dist/next/jobs/run-states.d.ts.map +0 -1
  1293. package/dist/next/jobs/run-states.js +0 -228
  1294. package/dist/next/jobs/run-states.js.map +0 -1
  1295. package/dist/next/jobs/run.d.ts +0 -113
  1296. package/dist/next/jobs/run.d.ts.map +0 -1
  1297. package/dist/next/jobs/run.js +0 -200
  1298. package/dist/next/jobs/run.js.map +0 -1
  1299. package/dist/next/jobs/running.d.ts +0 -44
  1300. package/dist/next/jobs/running.d.ts.map +0 -1
  1301. package/dist/next/jobs/running.js.map +0 -1
  1302. package/dist/next/jobs/stored.d.ts +0 -63
  1303. package/dist/next/jobs/stored.d.ts.map +0 -1
  1304. package/dist/next/jobs/stored.js.map +0 -1
  1305. package/dist/next/link/binary.d.ts.map +0 -1
  1306. package/dist/next/link/binary.js +0 -534
  1307. package/dist/next/link/binary.js.map +0 -1
  1308. package/dist/next/link/channel.d.ts +0 -63
  1309. package/dist/next/link/channel.d.ts.map +0 -1
  1310. package/dist/next/link/channel.js +0 -202
  1311. package/dist/next/link/channel.js.map +0 -1
  1312. package/dist/next/link/errors.d.ts.map +0 -1
  1313. package/dist/next/link/errors.js.map +0 -1
  1314. package/dist/next/link/index.d.ts.map +0 -1
  1315. package/dist/next/link/index.js.map +0 -1
  1316. package/dist/next/link/internal.d.ts.map +0 -1
  1317. package/dist/next/link/internal.js.map +0 -1
  1318. package/dist/next/link/ipc.d.ts.map +0 -1
  1319. package/dist/next/link/ipc.js.map +0 -1
  1320. package/dist/next/link/link.d.ts.map +0 -1
  1321. package/dist/next/link/link.js.map +0 -1
  1322. package/dist/next/link/message.d.ts +0 -249
  1323. package/dist/next/link/message.d.ts.map +0 -1
  1324. package/dist/next/link/message.js +0 -123
  1325. package/dist/next/link/message.js.map +0 -1
  1326. package/dist/next/link/part.d.ts +0 -80
  1327. package/dist/next/link/part.d.ts.map +0 -1
  1328. package/dist/next/link/part.js +0 -164
  1329. package/dist/next/link/part.js.map +0 -1
  1330. package/dist/next/link/text.d.ts.map +0 -1
  1331. package/dist/next/link/text.js +0 -335
  1332. package/dist/next/link/text.js.map +0 -1
  1333. package/dist/next/link/values.d.ts.map +0 -1
  1334. package/dist/next/link/values.js +0 -117
  1335. package/dist/next/link/values.js.map +0 -1
  1336. package/dist/next/link/websocket.d.ts.map +0 -1
  1337. package/dist/next/link/websocket.js.map +0 -1
  1338. package/dist/next/registries/contribution.d.ts.map +0 -1
  1339. package/dist/next/registries/contribution.js.map +0 -1
  1340. package/dist/next/registries/entries.d.ts.map +0 -1
  1341. package/dist/next/registries/entries.js.map +0 -1
  1342. package/dist/next/registries/index.d.ts.map +0 -1
  1343. package/dist/next/registries/index.js.map +0 -1
  1344. package/dist/next/registries/internal.d.ts.map +0 -1
  1345. package/dist/next/registries/internal.js.map +0 -1
  1346. package/dist/next/registries/record.d.ts +0 -94
  1347. package/dist/next/registries/record.d.ts.map +0 -1
  1348. package/dist/next/registries/record.js +0 -253
  1349. package/dist/next/registries/record.js.map +0 -1
  1350. package/dist/next/registries/registry.d.ts +0 -74
  1351. package/dist/next/registries/registry.d.ts.map +0 -1
  1352. package/dist/next/registries/registry.js.map +0 -1
  1353. package/dist/next/registries/value.d.ts.map +0 -1
  1354. package/dist/next/registries/value.js +0 -199
  1355. package/dist/next/registries/value.js.map +0 -1
  1356. package/dist/next/remote/calls.d.ts.map +0 -1
  1357. package/dist/next/remote/calls.js.map +0 -1
  1358. package/dist/next/remote/consumer.d.ts +0 -42
  1359. package/dist/next/remote/consumer.d.ts.map +0 -1
  1360. package/dist/next/remote/consumer.js +0 -343
  1361. package/dist/next/remote/consumer.js.map +0 -1
  1362. package/dist/next/remote/hold.d.ts +0 -130
  1363. package/dist/next/remote/hold.d.ts.map +0 -1
  1364. package/dist/next/remote/hold.js +0 -537
  1365. package/dist/next/remote/hold.js.map +0 -1
  1366. package/dist/next/remote/host-link.d.ts +0 -77
  1367. package/dist/next/remote/host-link.d.ts.map +0 -1
  1368. package/dist/next/remote/host-link.js +0 -182
  1369. package/dist/next/remote/host-link.js.map +0 -1
  1370. package/dist/next/remote/internal.d.ts.map +0 -1
  1371. package/dist/next/remote/internal.js.map +0 -1
  1372. package/dist/next/remote/path.d.ts.map +0 -1
  1373. package/dist/next/remote/path.js.map +0 -1
  1374. package/dist/next/remote/provider.d.ts +0 -76
  1375. package/dist/next/remote/provider.d.ts.map +0 -1
  1376. package/dist/next/remote/provider.js +0 -506
  1377. package/dist/next/remote/provider.js.map +0 -1
  1378. package/dist/next/remote/relay.d.ts +0 -58
  1379. package/dist/next/remote/relay.d.ts.map +0 -1
  1380. package/dist/next/remote/relay.js +0 -117
  1381. package/dist/next/remote/relay.js.map +0 -1
  1382. package/dist/next/remote/remote-object.d.ts +0 -133
  1383. package/dist/next/remote/remote-object.d.ts.map +0 -1
  1384. package/dist/next/remote/remote-object.js +0 -411
  1385. package/dist/next/remote/remote-object.js.map +0 -1
  1386. package/dist/next/remote/replica.d.ts +0 -59
  1387. package/dist/next/remote/replica.d.ts.map +0 -1
  1388. package/dist/next/remote/replica.js +0 -125
  1389. package/dist/next/remote/replica.js.map +0 -1
  1390. package/dist/next/state/batch.d.ts +0 -64
  1391. package/dist/next/state/batch.d.ts.map +0 -1
  1392. package/dist/next/state/batch.js +0 -163
  1393. package/dist/next/state/batch.js.map +0 -1
  1394. package/dist/next/state/derive.d.ts +0 -52
  1395. package/dist/next/state/derive.d.ts.map +0 -1
  1396. package/dist/next/state/derive.js +0 -182
  1397. package/dist/next/state/derive.js.map +0 -1
  1398. package/dist/next/state/index.d.ts +0 -6
  1399. package/dist/next/state/index.d.ts.map +0 -1
  1400. package/dist/next/state/index.js.map +0 -1
  1401. package/dist/next/state/internal.d.ts.map +0 -1
  1402. package/dist/next/state/internal.js.map +0 -1
  1403. package/dist/next/state/native-source.d.ts +0 -106
  1404. package/dist/next/state/native-source.d.ts.map +0 -1
  1405. package/dist/next/state/native-source.js +0 -240
  1406. package/dist/next/state/native-source.js.map +0 -1
  1407. package/dist/next/state/watchable.d.ts +0 -114
  1408. package/dist/next/state/watchable.d.ts.map +0 -1
  1409. package/dist/next/state/watchable.js +0 -156
  1410. package/dist/next/state/watchable.js.map +0 -1
  1411. package/dist/next/state/writable.d.ts +0 -32
  1412. package/dist/next/state/writable.d.ts.map +0 -1
  1413. package/dist/next/state/writable.js.map +0 -1
  1414. package/dist/next/store/adapter.d.ts +0 -67
  1415. package/dist/next/store/adapter.d.ts.map +0 -1
  1416. package/dist/next/store/adapter.js.map +0 -1
  1417. package/dist/next/store/allocator.d.ts.map +0 -1
  1418. package/dist/next/store/allocator.js.map +0 -1
  1419. package/dist/next/store/applier.d.ts.map +0 -1
  1420. package/dist/next/store/applier.js.map +0 -1
  1421. package/dist/next/store/apply-batch.d.ts +0 -12
  1422. package/dist/next/store/apply-batch.d.ts.map +0 -1
  1423. package/dist/next/store/apply-batch.js.map +0 -1
  1424. package/dist/next/store/archive.d.ts +0 -32
  1425. package/dist/next/store/archive.d.ts.map +0 -1
  1426. package/dist/next/store/archive.js +0 -129
  1427. package/dist/next/store/archive.js.map +0 -1
  1428. package/dist/next/store/backend.d.ts +0 -10
  1429. package/dist/next/store/backend.d.ts.map +0 -1
  1430. package/dist/next/store/backend.js.map +0 -1
  1431. package/dist/next/store/catalog.d.ts +0 -24
  1432. package/dist/next/store/catalog.d.ts.map +0 -1
  1433. package/dist/next/store/catalog.js.map +0 -1
  1434. package/dist/next/store/claims.d.ts.map +0 -1
  1435. package/dist/next/store/claims.js.map +0 -1
  1436. package/dist/next/store/columns.d.ts.map +0 -1
  1437. package/dist/next/store/columns.js.map +0 -1
  1438. package/dist/next/store/engine.d.ts +0 -176
  1439. package/dist/next/store/engine.d.ts.map +0 -1
  1440. package/dist/next/store/engine.js +0 -283
  1441. package/dist/next/store/engine.js.map +0 -1
  1442. package/dist/next/store/evaluate.d.ts +0 -17
  1443. package/dist/next/store/evaluate.d.ts.map +0 -1
  1444. package/dist/next/store/evaluate.js.map +0 -1
  1445. package/dist/next/store/export.d.ts +0 -17
  1446. package/dist/next/store/export.d.ts.map +0 -1
  1447. package/dist/next/store/export.js +0 -200
  1448. package/dist/next/store/export.js.map +0 -1
  1449. package/dist/next/store/expression.d.ts +0 -150
  1450. package/dist/next/store/expression.d.ts.map +0 -1
  1451. package/dist/next/store/expression.js.map +0 -1
  1452. package/dist/next/store/import.d.ts +0 -10
  1453. package/dist/next/store/import.d.ts.map +0 -1
  1454. package/dist/next/store/import.js +0 -276
  1455. package/dist/next/store/import.js.map +0 -1
  1456. package/dist/next/store/index.d.ts.map +0 -1
  1457. package/dist/next/store/index.js.map +0 -1
  1458. package/dist/next/store/json-column.d.ts +0 -33
  1459. package/dist/next/store/json-column.d.ts.map +0 -1
  1460. package/dist/next/store/json-column.js +0 -61
  1461. package/dist/next/store/json-column.js.map +0 -1
  1462. package/dist/next/store/jsonl.d.ts.map +0 -1
  1463. package/dist/next/store/jsonl.js.map +0 -1
  1464. package/dist/next/store/outbox.d.ts +0 -26
  1465. package/dist/next/store/outbox.d.ts.map +0 -1
  1466. package/dist/next/store/outbox.js.map +0 -1
  1467. package/dist/next/store/query.d.ts +0 -39
  1468. package/dist/next/store/query.d.ts.map +0 -1
  1469. package/dist/next/store/query.js.map +0 -1
  1470. package/dist/next/store/refusal.d.ts.map +0 -1
  1471. package/dist/next/store/refusal.js.map +0 -1
  1472. package/dist/next/store/rows.d.ts +0 -80
  1473. package/dist/next/store/rows.d.ts.map +0 -1
  1474. package/dist/next/store/rows.js.map +0 -1
  1475. package/dist/next/store/schema.d.ts +0 -25
  1476. package/dist/next/store/schema.d.ts.map +0 -1
  1477. package/dist/next/store/schema.js +0 -115
  1478. package/dist/next/store/schema.js.map +0 -1
  1479. package/dist/next/store/sql.d.ts +0 -73
  1480. package/dist/next/store/sql.d.ts.map +0 -1
  1481. package/dist/next/store/sql.js.map +0 -1
  1482. package/dist/next/store/step.d.ts +0 -48
  1483. package/dist/next/store/step.d.ts.map +0 -1
  1484. package/dist/next/store/step.js +0 -50
  1485. package/dist/next/store/step.js.map +0 -1
  1486. package/dist/next/store/store.d.ts +0 -161
  1487. package/dist/next/store/store.d.ts.map +0 -1
  1488. package/dist/next/store/store.js +0 -627
  1489. package/dist/next/store/store.js.map +0 -1
  1490. package/dist/next/store/table-changes.d.ts +0 -29
  1491. package/dist/next/store/table-changes.d.ts.map +0 -1
  1492. package/dist/next/store/table-changes.js.map +0 -1
  1493. package/dist/next/store/table-evolve.d.ts.map +0 -1
  1494. package/dist/next/store/table-evolve.js.map +0 -1
  1495. package/dist/next/store/table-handle.d.ts +0 -67
  1496. package/dist/next/store/table-handle.d.ts.map +0 -1
  1497. package/dist/next/store/table-handle.js +0 -101
  1498. package/dist/next/store/table-handle.js.map +0 -1
  1499. package/dist/next/store/table-history.d.ts.map +0 -1
  1500. package/dist/next/store/table-history.js.map +0 -1
  1501. package/dist/next/store/table-migration.d.ts +0 -16
  1502. package/dist/next/store/table-migration.d.ts.map +0 -1
  1503. package/dist/next/store/table-migration.js +0 -202
  1504. package/dist/next/store/table-migration.js.map +0 -1
  1505. package/dist/next/store/table-writes.d.ts.map +0 -1
  1506. package/dist/next/store/table-writes.js +0 -165
  1507. package/dist/next/store/table-writes.js.map +0 -1
  1508. package/dist/next/store/table.d.ts +0 -80
  1509. package/dist/next/store/table.d.ts.map +0 -1
  1510. package/dist/next/store/table.js.map +0 -1
  1511. package/dist/next/store/text.d.ts.map +0 -1
  1512. package/dist/next/store/text.js.map +0 -1
  1513. package/dist/next/store/writes.d.ts.map +0 -1
  1514. package/dist/next/store/writes.js.map +0 -1
  1515. package/dist/next-node/compression.d.ts +0 -7
  1516. package/dist/next-node/compression.d.ts.map +0 -1
  1517. package/dist/next-node/compression.js +0 -24
  1518. package/dist/next-node/compression.js.map +0 -1
  1519. package/dist/next-node/http/admission.d.ts.map +0 -1
  1520. package/dist/next-node/http/admission.js.map +0 -1
  1521. package/dist/next-node/http/authenticate.d.ts +0 -21
  1522. package/dist/next-node/http/authenticate.d.ts.map +0 -1
  1523. package/dist/next-node/http/authenticate.js +0 -34
  1524. package/dist/next-node/http/authenticate.js.map +0 -1
  1525. package/dist/next-node/http/cookies.d.ts +0 -24
  1526. package/dist/next-node/http/cookies.d.ts.map +0 -1
  1527. package/dist/next-node/http/cookies.js +0 -62
  1528. package/dist/next-node/http/cookies.js.map +0 -1
  1529. package/dist/next-node/http/file.d.ts.map +0 -1
  1530. package/dist/next-node/http/file.js.map +0 -1
  1531. package/dist/next-node/http/headers.d.ts.map +0 -1
  1532. package/dist/next-node/http/headers.js +0 -129
  1533. package/dist/next-node/http/headers.js.map +0 -1
  1534. package/dist/next-node/http/http.d.ts +0 -100
  1535. package/dist/next-node/http/http.d.ts.map +0 -1
  1536. package/dist/next-node/http/http.js +0 -462
  1537. package/dist/next-node/http/http.js.map +0 -1
  1538. package/dist/next-node/http/incoming.d.ts.map +0 -1
  1539. package/dist/next-node/http/incoming.js.map +0 -1
  1540. package/dist/next-node/http/index.d.ts +0 -11
  1541. package/dist/next-node/http/index.d.ts.map +0 -1
  1542. package/dist/next-node/http/index.js +0 -12
  1543. package/dist/next-node/http/index.js.map +0 -1
  1544. package/dist/next-node/http/node.d.ts.map +0 -1
  1545. package/dist/next-node/http/node.js.map +0 -1
  1546. package/dist/next-node/http/request.d.ts +0 -54
  1547. package/dist/next-node/http/request.d.ts.map +0 -1
  1548. package/dist/next-node/http/request.js +0 -116
  1549. package/dist/next-node/http/request.js.map +0 -1
  1550. package/dist/next-node/http/response.d.ts +0 -63
  1551. package/dist/next-node/http/response.d.ts.map +0 -1
  1552. package/dist/next-node/http/response.js.map +0 -1
  1553. package/dist/next-node/http/router.d.ts +0 -114
  1554. package/dist/next-node/http/router.d.ts.map +0 -1
  1555. package/dist/next-node/http/router.js +0 -261
  1556. package/dist/next-node/http/router.js.map +0 -1
  1557. package/dist/next-node/http/upgrades.d.ts +0 -58
  1558. package/dist/next-node/http/upgrades.d.ts.map +0 -1
  1559. package/dist/next-node/http/upgrades.js +0 -184
  1560. package/dist/next-node/http/upgrades.js.map +0 -1
  1561. package/dist/next-node/plugins/build.d.ts +0 -57
  1562. package/dist/next-node/plugins/build.d.ts.map +0 -1
  1563. package/dist/next-node/plugins/build.js +0 -334
  1564. package/dist/next-node/plugins/build.js.map +0 -1
  1565. package/dist/next-node/plugins/discover.d.ts +0 -36
  1566. package/dist/next-node/plugins/discover.d.ts.map +0 -1
  1567. package/dist/next-node/plugins/discover.js +0 -91
  1568. package/dist/next-node/plugins/discover.js.map +0 -1
  1569. package/dist/next-node/plugins/evaluate.d.ts +0 -33
  1570. package/dist/next-node/plugins/evaluate.d.ts.map +0 -1
  1571. package/dist/next-node/plugins/evaluate.js +0 -98
  1572. package/dist/next-node/plugins/evaluate.js.map +0 -1
  1573. package/dist/next-node/plugins/index.d.ts +0 -9
  1574. package/dist/next-node/plugins/index.d.ts.map +0 -1
  1575. package/dist/next-node/plugins/index.js +0 -11
  1576. package/dist/next-node/plugins/index.js.map +0 -1
  1577. package/dist/next-node/plugins/install.d.ts +0 -13
  1578. package/dist/next-node/plugins/install.d.ts.map +0 -1
  1579. package/dist/next-node/plugins/install.js +0 -37
  1580. package/dist/next-node/plugins/install.js.map +0 -1
  1581. package/dist/next-node/plugins/plugins.d.ts +0 -135
  1582. package/dist/next-node/plugins/plugins.d.ts.map +0 -1
  1583. package/dist/next-node/plugins/plugins.js +0 -206
  1584. package/dist/next-node/plugins/plugins.js.map +0 -1
  1585. package/dist/next-node/plugins/runtime.d.ts +0 -41
  1586. package/dist/next-node/plugins/runtime.d.ts.map +0 -1
  1587. package/dist/next-node/plugins/runtime.js +0 -136
  1588. package/dist/next-node/plugins/runtime.js.map +0 -1
  1589. package/dist/next-node/plugins/stack.d.ts.map +0 -1
  1590. package/dist/next-node/plugins/stack.js.map +0 -1
  1591. package/dist/next-node/plugins/watcher.d.ts +0 -58
  1592. package/dist/next-node/plugins/watcher.d.ts.map +0 -1
  1593. package/dist/next-node/plugins/watcher.js +0 -281
  1594. package/dist/next-node/plugins/watcher.js.map +0 -1
  1595. package/dist/next-node/workers/control.d.ts +0 -83
  1596. package/dist/next-node/workers/control.d.ts.map +0 -1
  1597. package/dist/next-node/workers/control.js +0 -77
  1598. package/dist/next-node/workers/control.js.map +0 -1
  1599. package/dist/next-node/workers/index.d.ts +0 -5
  1600. package/dist/next-node/workers/index.d.ts.map +0 -1
  1601. package/dist/next-node/workers/index.js +0 -7
  1602. package/dist/next-node/workers/index.js.map +0 -1
  1603. package/dist/next-node/workers/lock.d.ts +0 -21
  1604. package/dist/next-node/workers/lock.d.ts.map +0 -1
  1605. package/dist/next-node/workers/lock.js +0 -137
  1606. package/dist/next-node/workers/lock.js.map +0 -1
  1607. package/dist/next-node/workers/main.d.ts +0 -46
  1608. package/dist/next-node/workers/main.d.ts.map +0 -1
  1609. package/dist/next-node/workers/main.js +0 -230
  1610. package/dist/next-node/workers/main.js.map +0 -1
  1611. package/dist/next-node/workers/process.d.ts +0 -42
  1612. package/dist/next-node/workers/process.d.ts.map +0 -1
  1613. package/dist/next-node/workers/process.js +0 -125
  1614. package/dist/next-node/workers/process.js.map +0 -1
  1615. package/dist/next-node/workers/workers.d.ts +0 -80
  1616. package/dist/next-node/workers/workers.d.ts.map +0 -1
  1617. package/dist/next-node/workers/workers.js +0 -572
  1618. package/dist/next-node/workers/workers.js.map +0 -1
  1619. package/dist/node.d.ts +0 -4
  1620. package/dist/node.d.ts.map +0 -1
  1621. package/dist/node.js +0 -4
  1622. package/dist/node.js.map +0 -1
  1623. package/dist/object.d.ts +0 -438
  1624. package/dist/object.d.ts.map +0 -1
  1625. package/dist/object.js +0 -1570
  1626. package/dist/object.js.map +0 -1
  1627. package/dist/publish.d.ts +0 -5
  1628. package/dist/publish.d.ts.map +0 -1
  1629. package/dist/publish.js +0 -40
  1630. package/dist/publish.js.map +0 -1
  1631. package/dist/registry.d.ts +0 -25
  1632. package/dist/registry.d.ts.map +0 -1
  1633. package/dist/registry.js +0 -6
  1634. package/dist/registry.js.map +0 -1
  1635. package/dist/reload.d.ts +0 -126
  1636. package/dist/reload.d.ts.map +0 -1
  1637. package/dist/reload.js +0 -653
  1638. package/dist/reload.js.map +0 -1
  1639. package/dist/remote.d.ts +0 -165
  1640. package/dist/remote.d.ts.map +0 -1
  1641. package/dist/remote.js +0 -612
  1642. package/dist/remote.js.map +0 -1
  1643. package/dist/schema.d.ts +0 -25
  1644. package/dist/schema.d.ts.map +0 -1
  1645. package/dist/schema.js +0 -403
  1646. package/dist/schema.js.map +0 -1
  1647. package/dist/state.d.ts +0 -92
  1648. package/dist/state.d.ts.map +0 -1
  1649. package/dist/state.js +0 -287
  1650. package/dist/state.js.map +0 -1
  1651. package/dist/types.d.ts +0 -88
  1652. package/dist/types.d.ts.map +0 -1
  1653. package/dist/types.js +0 -2
  1654. package/dist/types.js.map +0 -1
  1655. package/dist/websocket.d.ts +0 -15
  1656. package/dist/websocket.d.ts.map +0 -1
  1657. package/dist/websocket.js +0 -16
  1658. package/dist/websocket.js.map +0 -1
  1659. package/dist/wire.d.ts +0 -197
  1660. package/dist/wire.d.ts.map +0 -1
  1661. package/dist/wire.js +0 -166
  1662. package/dist/wire.js.map +0 -1
  1663. package/docs/guide.md +0 -814
  1664. package/docs/next/benchmarks.md +0 -959
  1665. package/docs/next/decisions.md +0 -2957
  1666. package/docs/next/dependencies/book.md +0 -1671
  1667. package/docs/next/dependencies/index.html +0 -2641
  1668. package/docs/next/design.md +0 -2554
  1669. package/docs/next/durable-observers/book.md +0 -432
  1670. package/docs/next/durable-observers/index.html +0 -517
  1671. package/docs/next/guide-plugins-hosts/book.md +0 -607
  1672. package/docs/next/guide-plugins-hosts/index.html +0 -652
  1673. package/docs/next/http-workers/book.md +0 -378
  1674. package/docs/next/http-workers/index.html +0 -515
  1675. package/docs/next/layer-1.md +0 -311
  1676. package/docs/next/layer-2.md +0 -216
  1677. package/docs/next/plugin-model/book.md +0 -186
  1678. package/docs/next/plugin-model/index.html +0 -310
  1679. package/docs/next/plugin-primer/book.md +0 -273
  1680. package/docs/next/plugin-primer/index.html +0 -430
  1681. package/docs/next/slice-1.md +0 -236
  1682. package/docs/next/slice-10.md +0 -285
  1683. package/docs/next/slice-11.md +0 -93
  1684. package/docs/next/slice-2.md +0 -174
  1685. package/docs/next/slice-3a.md +0 -296
  1686. package/docs/next/slice-3b.md +0 -197
  1687. package/docs/next/slice-4a.md +0 -418
  1688. package/docs/next/slice-4b.md +0 -208
  1689. package/docs/next/slice-6a.md +0 -676
  1690. package/docs/next/slice-6b.md +0 -332
  1691. package/docs/next/slice-7b/book.md +0 -608
  1692. package/docs/next/slice-7b/index.html +0 -842
  1693. package/docs/next/slice-7b.md +0 -255
  1694. package/docs/next/slice-7c.md +0 -165
  1695. package/docs/next/slices.md +0 -230
  1696. package/docs/next/store/book.md +0 -665
  1697. package/docs/next/store/index.html +0 -861
  1698. package/docs/next/store/walkthrough.md +0 -193
  1699. package/docs/spec.md +0 -288
  1700. package/docs/tutorial.md +0 -932
  1701. /package/dist/{next/contracts → contracts}/accepts.js +0 -0
  1702. /package/dist/{next/contracts → contracts}/contract.js +0 -0
  1703. /package/dist/{next/contracts → contracts}/declare.d.ts +0 -0
  1704. /package/dist/{next/contracts → contracts}/declare.js +0 -0
  1705. /package/dist/{next/contracts → contracts}/evolve.d.ts +0 -0
  1706. /package/dist/{next/contracts → contracts}/evolve.js +0 -0
  1707. /package/dist/{next/contracts → contracts}/fingerprint.js +0 -0
  1708. /package/dist/{next/contracts → contracts}/history.d.ts +0 -0
  1709. /package/dist/{next/contracts → contracts}/history.js +0 -0
  1710. /package/dist/{next/contracts → contracts}/host-kind.d.ts +0 -0
  1711. /package/dist/{next/contracts → contracts}/host-kind.js +0 -0
  1712. /package/dist/{next/contracts → contracts}/index.d.ts +0 -0
  1713. /package/dist/{next/contracts → contracts}/index.js +0 -0
  1714. /package/dist/{next/contracts → contracts}/internal.d.ts +0 -0
  1715. /package/dist/{next/contracts → contracts}/internal.js +0 -0
  1716. /package/dist/{next/contracts → contracts}/names.d.ts +0 -0
  1717. /package/dist/{next/contracts → contracts}/names.js +0 -0
  1718. /package/dist/{next/contracts → contracts}/params.js +0 -0
  1719. /package/dist/{next/contracts → contracts}/schema.d.ts +0 -0
  1720. /package/dist/{next/contracts → contracts}/schema.js +0 -0
  1721. /package/dist/{next/data → data}/args.js +0 -0
  1722. /package/dist/{next/data → data}/failure.d.ts +0 -0
  1723. /package/dist/{next/data → data}/params.js +0 -0
  1724. /package/dist/{next/documents → documents}/address-source.js +0 -0
  1725. /package/dist/{next/documents → documents}/fence.d.ts +0 -0
  1726. /package/dist/{next/documents → documents}/fence.js +0 -0
  1727. /package/dist/{next/documents → documents}/handles.js +0 -0
  1728. /package/dist/{next/documents → documents}/index.d.ts +0 -0
  1729. /package/dist/{next/documents → documents}/index.js +0 -0
  1730. /package/dist/{next/documents → documents}/internal.js +0 -0
  1731. /package/dist/{next/documents → documents}/line.d.ts +0 -0
  1732. /package/dist/{next/documents → documents}/line.js +0 -0
  1733. /package/dist/{next/documents → documents}/residency.js +0 -0
  1734. /package/dist/{next/host → host}/adapted.js +0 -0
  1735. /package/dist/{next/host → host}/backoff.d.ts +0 -0
  1736. /package/dist/{next/host → host}/backoff.js +0 -0
  1737. /package/dist/{next/host → host}/deadline.d.ts +0 -0
  1738. /package/dist/{next/host → host}/deadline.js +0 -0
  1739. /package/dist/{next/host → host}/dependencies.d.ts +0 -0
  1740. /package/dist/{next/host → host}/dependencies.js +0 -0
  1741. /package/dist/{next/host → host}/destination.js +0 -0
  1742. /package/dist/{next/host → host}/facet.js +0 -0
  1743. /package/dist/{next/host → host}/follow.js +0 -0
  1744. /package/dist/{next/host → host}/index.js +0 -0
  1745. /package/dist/{next/host → host}/members.js +0 -0
  1746. /package/dist/{next/host → host}/parked.js +0 -0
  1747. /package/dist/{next/host → host}/presence.js +0 -0
  1748. /package/dist/{next/host → host}/retry-on.d.ts +0 -0
  1749. /package/dist/{next/host → host}/retry-on.js +0 -0
  1750. /package/dist/{next/host → host}/revocation.js +0 -0
  1751. /package/dist/{next/host → host}/sleep.js +0 -0
  1752. /package/dist/{next/host → host}/uuid.d.ts +0 -0
  1753. /package/dist/{next/host → host}/uuid.js +0 -0
  1754. /package/dist/{next/jobs → jobs}/definition.d.ts +0 -0
  1755. /package/dist/{next/jobs → jobs}/definition.js +0 -0
  1756. /package/dist/{next/jobs → jobs}/index.d.ts +0 -0
  1757. /package/dist/{next/jobs → jobs}/index.js +0 -0
  1758. /package/dist/{next/jobs → jobs}/internal.d.ts +0 -0
  1759. /package/dist/{next/jobs → jobs}/internal.js +0 -0
  1760. /package/dist/{next/jobs → jobs}/persisted.js +0 -0
  1761. /package/dist/{next/jobs → jobs}/running.js +0 -0
  1762. /package/dist/{next/jobs → jobs}/stored.js +0 -0
  1763. /package/dist/{next/link → link}/binary.d.ts +0 -0
  1764. /package/dist/{next/link → link}/errors.d.ts +0 -0
  1765. /package/dist/{next/link → link}/errors.js +0 -0
  1766. /package/dist/{next/link → link}/index.d.ts +0 -0
  1767. /package/dist/{next/link → link}/index.js +0 -0
  1768. /package/dist/{next/link → link}/internal.d.ts +0 -0
  1769. /package/dist/{next/link → link}/internal.js +0 -0
  1770. /package/dist/{next/link → link}/ipc.d.ts +0 -0
  1771. /package/dist/{next/link → link}/ipc.js +0 -0
  1772. /package/dist/{next/link → link}/link.d.ts +0 -0
  1773. /package/dist/{next/link → link}/link.js +0 -0
  1774. /package/dist/{next/link → link}/text.d.ts +0 -0
  1775. /package/dist/{next/link → link}/values.d.ts +0 -0
  1776. /package/dist/{next/link → link}/websocket.d.ts +0 -0
  1777. /package/dist/{next/link → link}/websocket.js +0 -0
  1778. /package/dist/{next-node → node}/http/admission.d.ts +0 -0
  1779. /package/dist/{next-node → node}/http/admission.js +0 -0
  1780. /package/dist/{next-node → node}/http/file.d.ts +0 -0
  1781. /package/dist/{next-node → node}/http/file.js +0 -0
  1782. /package/dist/{next-node → node}/http/headers.d.ts +0 -0
  1783. /package/dist/{next-node → node}/http/incoming.d.ts +0 -0
  1784. /package/dist/{next-node → node}/http/incoming.js +0 -0
  1785. /package/dist/{next-node → node}/http/node.d.ts +0 -0
  1786. /package/dist/{next-node → node}/http/node.js +0 -0
  1787. /package/dist/{next-node → node}/http/response.js +0 -0
  1788. /package/dist/{next-node → node}/plugins/stack.d.ts +0 -0
  1789. /package/dist/{next-node → node}/plugins/stack.js +0 -0
  1790. /package/dist/{next/registries → registries}/contribution.d.ts +0 -0
  1791. /package/dist/{next/registries → registries}/contribution.js +0 -0
  1792. /package/dist/{next/registries → registries}/entries.d.ts +0 -0
  1793. /package/dist/{next/registries → registries}/entries.js +0 -0
  1794. /package/dist/{next/registries → registries}/index.d.ts +0 -0
  1795. /package/dist/{next/registries → registries}/index.js +0 -0
  1796. /package/dist/{next/registries → registries}/internal.d.ts +0 -0
  1797. /package/dist/{next/registries → registries}/internal.js +0 -0
  1798. /package/dist/{next/registries → registries}/registry.js +0 -0
  1799. /package/dist/{next/registries → registries}/value.d.ts +0 -0
  1800. /package/dist/{next/remote → remote}/calls.d.ts +0 -0
  1801. /package/dist/{next/remote → remote}/calls.js +0 -0
  1802. /package/dist/{next/remote → remote}/internal.d.ts +0 -0
  1803. /package/dist/{next/remote → remote}/internal.js +0 -0
  1804. /package/dist/{next/remote → remote}/path.d.ts +0 -0
  1805. /package/dist/{next/remote → remote}/path.js +0 -0
  1806. /package/dist/{next/state → state}/index.js +0 -0
  1807. /package/dist/{next/state → state}/internal.d.ts +0 -0
  1808. /package/dist/{next/state → state}/internal.js +0 -0
  1809. /package/dist/{next/state → state}/writable.js +0 -0
  1810. /package/dist/{next/store → store}/adapter.js +0 -0
  1811. /package/dist/{next/store → store}/allocator.d.ts +0 -0
  1812. /package/dist/{next/store → store}/allocator.js +0 -0
  1813. /package/dist/{next/store → store}/applier.d.ts +0 -0
  1814. /package/dist/{next/store → store}/applier.js +0 -0
  1815. /package/dist/{next/store → store}/apply-batch.js +0 -0
  1816. /package/dist/{next/store → store}/backend.js +0 -0
  1817. /package/dist/{next/store → store}/catalog.js +0 -0
  1818. /package/dist/{next/store → store}/claims.d.ts +0 -0
  1819. /package/dist/{next/store → store}/claims.js +0 -0
  1820. /package/dist/{next/store → store}/columns.d.ts +0 -0
  1821. /package/dist/{next/store → store}/columns.js +0 -0
  1822. /package/dist/{next/store → store}/evaluate.js +0 -0
  1823. /package/dist/{next/store → store}/expression.js +0 -0
  1824. /package/dist/{next/store → store}/index.d.ts +0 -0
  1825. /package/dist/{next/store → store}/index.js +0 -0
  1826. /package/dist/{next/store → store}/jsonl.d.ts +0 -0
  1827. /package/dist/{next/store → store}/jsonl.js +0 -0
  1828. /package/dist/{next/store → store}/outbox.js +0 -0
  1829. /package/dist/{next/store → store}/query.js +0 -0
  1830. /package/dist/{next/store → store}/refusal.d.ts +0 -0
  1831. /package/dist/{next/store → store}/refusal.js +0 -0
  1832. /package/dist/{next/store → store}/rows.js +0 -0
  1833. /package/dist/{next/store → store}/sql.js +0 -0
  1834. /package/dist/{next/store → store}/table-changes.js +0 -0
  1835. /package/dist/{next/store → store}/table-evolve.d.ts +0 -0
  1836. /package/dist/{next/store → store}/table-evolve.js +0 -0
  1837. /package/dist/{next/store → store}/table-history.d.ts +0 -0
  1838. /package/dist/{next/store → store}/table-history.js +0 -0
  1839. /package/dist/{next/store → store}/table-writes.d.ts +0 -0
  1840. /package/dist/{next/store → store}/table.js +0 -0
  1841. /package/dist/{next/store → store}/text.d.ts +0 -0
  1842. /package/dist/{next/store → store}/text.js +0 -0
  1843. /package/dist/{next/store → store}/writes.d.ts +0 -0
  1844. /package/dist/{next/store → store}/writes.js +0 -0
  1845. /package/docs/{next/dependencies → dependencies}/model.md +0 -0
  1846. /package/docs/{next/flow-control → flow-control}/book.md +0 -0
  1847. /package/docs/{next/flow-control → flow-control}/fold/index.html +0 -0
  1848. /package/docs/{next/flow-control → flow-control}/index.html +0 -0
  1849. /package/docs/{next/flow-control → flow-control}/window/index.html +0 -0
  1850. /package/docs/{next/slice-4.md → slice-4.md} +0 -0
  1851. /package/docs/{next/slice-5.md → slice-5.md} +0 -0
  1852. /package/docs/{next/slice-7a.md → slice-7a.md} +0 -0
  1853. /package/docs/{next/slice-8.md → slice-8.md} +0 -0
@@ -1,2554 +0,0 @@
1
- # Chord v2: target design
2
-
3
- The design of Chord v2 (`packages/chord/src/next`, export `@earendil-works/chord/next`) and of how apps (the
4
- playground, p3) use it: **the one current statement of every rule** (owner, 2026-10-24). Every decision is recorded in
5
- the decision log `packages/chord/docs/next/decisions.md` (the history and the reasons, kept complete) and folded into this
6
- document in the same commit. Where a rule is built, the slice is named (`slices.md`); the code follows this document.
7
- It replaces `apps/p2/docs/target-design.md`.
8
-
9
- Marks: everything is decided unless marked **Decision needed** (problem with an example, then options; nothing in such
10
- a block is settled; section 26 lists them all). **(carried over)** marks behaviour of today's Chord that v2 keeps
11
- without a new decision. API names are working names.
12
-
13
- Contents: 1 goals · 2 concepts · 3 hosts and links · 4 principals · 5 object types · 6 objects · 7 references · 8 ctx ·
14
- 9 documents · 10 store and storage · 11 kinds of state · 12 derives · 13 natives · 14 routines · 15 jobs · 16 the facet
15
- · 17 registries · 18 start data and platform bindings · 19 presence · 20 input into running work · 21 reload and rollout
16
- · 22 wire · 23 optional components · 24 Durable integration · 25 apps: ownership and porting · 26 decisions needed · 27
17
- versions and adapters · 28 building: slices · 29 telemetry · 30 cost model · 31 rejected
18
-
19
- ---
20
-
21
- ## 1. Goals and principles
22
-
23
- 1. **Reload without restarts.** A plugin's new code takes over inside the running app: hosts keep running; data, open
24
- connections and running work survive where they can. Reloads are explicit (a button or a command), never on save.
25
- Base code (Chord, the app runtime) restarts the hosts.
26
- 2. **Ownership.** Every thing has exactly one owning object, the smallest it belongs to. The owner holds the data,
27
- enforces its rules in its methods and offers the operations others need. Nobody reaches past it.
28
- 3. **Factories declare, Chord activates.** A factory is synchronous and only declares; Chord performs activation.
29
- Handles a factory gets are valid for the object's whole life.
30
- 4. **Natives only in objects.** OS-level values are opened and closed by the object that owns them, and reach other
31
- plugins only through that owner's methods, state or registry entries.
32
- 5. **Errors look like disconnects.** No request-id framework; consumers handle a failed call as they handle a dropped
33
- link. References re-hold by themselves.
34
- 6. **Tagged unions, always.** States, results and outcomes are discriminated by `kind`; each state carries exactly its
35
- own fields.
36
- 7. **Portable kernel.** A host is a logical identity plus an incarnation; facets may come pre-imported; values are
37
- JSON plus bytes independent of the transport. Node first; Cloudflare Durable Objects and similar stay possible.
38
- 8. **Context last.** Parameters are the required arguments, then the context (`ctx` or a Durable `Context`), then
39
- optional arguments: `self.tx(fn, ctx)`, `handle.change(key, fn, ctx)`, `chord(fn, context)`, `job.start(args, ctx,
40
- { key })` (owner, 2026-10-21).
41
- 9. **Few concepts, no ceremony.** No special directories, no `defineNative`, no lints standing in for design.
42
- 10. **Aligned with Durable** (owner, 2026-10-27): where Chord and Durable solve the same problem (commits, lines,
43
- loads, storage errors, watches), they use the same rules and mechanisms.
44
-
45
- ---
46
-
47
- ## 2. Concepts
48
-
49
- | Concept | What it is |
50
- | --- | --- |
51
- | host | one participant (a process, a tab, a DO): a logical identity plus an incarnation |
52
- | link | a connection between two hosts |
53
- | host kind / address | typed description of addressable hosts / one host of a kind (`Session({ id })`) |
54
- | facet | a plugin's declarations for one host kind: the types it serves, its contributions; no state or behaviour of its own |
55
- | object type | a contract: name, params (which instance), host address, members, version |
56
- | object | one instance per (type, params, principal key); `local`: per (type, params) |
57
- | principal | who calls; stamped by links, typed by the app |
58
- | reference | what `get` returns; keeps its object alive; live and hydrated when awaited |
59
- | document | a named JSON value an object owns, written in transactions |
60
- | derive | a value computed from watchables |
61
- | native | an OS-level value opened with `self.open`; only in objects |
62
- | routine | standing behaviour of an object: `self.on(source, fn)`, `self.onLive(fn)` |
63
- | job | owned work a call starts that outlives it: intent, run, finish; optional state document per run |
64
- | registry | an owner's extension point: one contribution per contributor, composed by the owner |
65
- | shared store | a `local` object holding shared data once, behind per-principal `remote` views |
66
- | `ctx` | per call: cancellation, principal, call-scoped references |
67
- | revision | (server incarnation, sequence): the complete code set a host runs |
68
-
69
- ---
70
-
71
- ## 3. Hosts and links
72
-
73
- ### Roles
74
-
75
- A Node app has one shape:
76
-
77
- ```
78
- client client client browsers, TUIs: not addressable
79
- └──────┼──────┘
80
- server exactly one, addressable
81
- ┌──────┼──────┐
82
- worker worker worker addressable by a typed address, started on demand
83
- ```
84
-
85
- | Role | Addressable | Principal comes from | Lifecycle |
86
- | --- | --- | --- | --- |
87
- | client | no | authentication of its link | connects by itself |
88
- | server | yes, one | its own declaration | runs |
89
- | worker | yes, many | stamped by the parent | started on demand by the app |
90
-
91
- Clients serve only `local` types (they are not addressable): a host without a principal or without an address refuses
92
- to serve a remote type (a declaration error: `load` leaves that plugin out and reports it, a reload keeps it on its
93
- old code; a remote object is owned by a principal of the host serving it, owner,
94
- 2026-10-24; and placed by its host address, owner, 2026-10-29). No client providers for now (owner,
95
- 2026-10-28): client-side capabilities (a camera, WebMCP tools) go through an owner's requests that clients answer
96
- (section 20, the Questions service). A client's local
97
- calls have no principal; what a client calls on the server is stamped with the client's authenticated principal.
98
- Clients reach workers only through the server, which relays; workers reach each other through the server too. A
99
- detached process (e.g. a terminal host) would be another child kind of the server. Things that are not hosts: a code
100
- mode sandbox (a worker thread inside a worker), remote environment daemons (their own protocol, owned by an object),
101
- the TUI sandbox behind its launcher (the launcher only passes frames). A Durable Object deployment is a mesh routed by
102
- the edge (section 24 and the research note).
103
-
104
- ### Host kinds and addresses
105
-
106
- ```ts
107
- export const Server = hostKind("server");
108
- export const Session = hostKind("session", { id: str() }); // params like a contract's
109
-
110
- export const Notes = remote("notes", {
111
- version: 1,
112
- params: { session: str() }, // flat record of required scalars
113
- hostAddress: ({ session }) => Session({ id: session }), // a typed function of the params
114
- variants: { … },
115
- });
116
- export const Catalog = remote("catalog", { hostAddress: () => Server(), … });
117
- ```
118
-
119
- - `hostKind(name, params?)` declares a kind of addressable host; its params follow the params policy of contracts
120
- (section 5). `Session({ id: "S1" })` is an **address**: `{ kind, params, key }`, the key built like an identity key
121
- (`session|S1`); two addresses are equal when their keys are. No host-name strings appear in app code.
122
- - **`hostAddress`** (owner, 2026-10-21 as `placement`, renamed 2026-10-29) is a typed function of the params returning
123
- the address of the host that serves the object, required on every `remote` contract (owner, 2026-10-29); `local`
124
- contracts have none. It is not part of the contract fingerprint; a changed rule surfaces as a refusal (below).
125
- - **`params`** (owner, 2026-10-21; was `input`) select the instance among objects of its type and are part of its
126
- identity (section 5).
127
- - **The caller computes the address** and sends it in the `hold`; a host that relays routes by that address alone and
128
- never needs the contract or parses params. **The provider computes it again** from the params: a hold naming this
129
- host whose params the provider's code places elsewhere (code skew) waits unbound `version` (`failed { waiting }`,
130
- `invalid/host_address`, dependency model §1; slice 7a); a hold naming another host's address is relayed, never served
131
- here (misrouted holds are never captured by a relay that serves the same name).
132
- - **Every reference is a request** (dependency model, slice 7a): it has one holder (an attempt, a call, outside code,
133
- a link's peer) and ends only when its holder ends it (release, a call settling, a getter giving up, the peer's link
134
- or origin closing, revocation, the host closing), never because its provider is missing, went away or does not fit.
135
- - **Where a reference made on a host, or a hold arriving on one of its links, goes**, by address alone (slice 4a;
136
- slice 7a: no same-name check on the consumer's host):
137
-
138
- | Case | Goes |
139
- | --- | --- |
140
- | a `local` type | here |
141
- | a `remote` type whose host address (computed here from the params) is this host's address, served here or not | here |
142
- | an arriving hold naming this host's address | here |
143
- | the address (computed, or named by the hold) is of a kind this host has a route for | over that route's link (the address's params checked against the kind, then `authorize`) |
144
- | otherwise (a remote type) | over the parent link; a hold that arrived *on* the parent link is never sent back to it: `unavailable` |
145
- | no parent link: the host never had one | `unavailable` |
146
- | no parent link: it is down (a drop) | waits on the parent path, `loading`, until the next link (design audit, 2026-10-27) |
147
-
148
- A `hostAddress` or `authorize` that throws fails the request broken with that error; an address whose params fail
149
- the kind's check is broken `invalid/host_address`.
150
- - **The publication gate** (slice 7a): a request made on this host, or a hold arriving on its links, before the
151
- host's first publication (`load`'s batch of declarations) is not placed yet: it is `loading`, and the publication
152
- places it. The gate lasts only for the synchronous setups, never for activation, so it cannot deadlock.
153
- - **Then the selected provider is checked** (here: served, the version and fingerprint, the params, the provider's
154
- own host-address check; over a path: at the provider host). Version checks never look at a same-name registration
155
- elsewhere. What the check finds:
156
-
157
- | The check finds | The request |
158
- | --- | --- |
159
- | a fitting provider | bound (to the object here, or to the hold over a path) |
160
- | not published yet | unbound `unpublished`: `loading` |
161
- | nobody serves the name at its address (or serves it as the other kind) | unbound `not_served`: `failed { waiting }` (`unavailable` "X is not served here") |
162
- | no fitting version, a fingerprint that differs at the same version, a host address the provider computes elsewhere | unbound `version`: `failed { waiting }` (`contract_mismatch`, `invalid/host_address`) |
163
- | a registry served, but its first `compose` (or the reader's version mapping) threw | unbound `compose`: `failed { waiting }` (§17) |
164
- | the path has no link (a drop, a route resolving) | on the path: `loading` |
165
- | `authorize` refused, invalid params, a cycle | `failed { broken }`, never indexed |
166
-
167
- The unbound reasons that wait for a name are indexed under it on the host that decided them: the consumer's host
168
- for a request made there, the provider's host for a hold that arrived over a link (kept refused there; a `retry`
169
- re-runs its start). A publication serving a name (`load`'s, or a reload's commit, which wakes only the requests of
170
- the names it serves, slice 7b) wakes its requests, which run their check again
171
- (a refused hold sends `loading`, then `bound` or `failed`); no new message kind. Index entries go when their request
172
- ends (GC-tested). The consumer never re-holds a request by itself: no backoff, no polling.
173
-
174
- ### The low-level host API
175
-
176
- ```ts
177
- // server.ts
178
- const server = createHost<P>({ address: Server(), principal: { kind: "server" }, onError });
179
- server.route(Session, {
180
- authorize: (p, address) => p.kind === "owner" || p.kind === "server" || (p.kind === "guest" && p.session === address.params.id),
181
- resolve: async (address, context) => {
182
- const child = fork("worker.ts", [], { serialization: "advanced" }); // no `signal`: see below
183
- child.send({ id: address.params.id, init: await initFor(address.params.id) }); // the app's own start message
184
- return { link: ipcLink(child), principal: { kind: "worker", session: address.params.id }, trusted: true };
185
- },
186
- });
187
- await server.load([{ name: "@app/core", facet: coreServerFacet(config) }, ...serverPlugins], ctx);
188
-
189
- wss.on("connection", (ws, req) => { // an entry point: app or adapter code
190
- const principal = authenticate(req);
191
- if (!principal) return ws.close(4401);
192
- server.accept(webSocketLink(ws), { principal }, ctx);
193
- });
194
- radius.onChannel((ws) => server.accept(webSocketLink(ws), { principal: { kind: "owner", access: "relay" } }, ctx));
195
- ```
196
-
197
- ```ts
198
- // worker.ts: connect first (W6), then load; start data through the core facet (section 18)
199
- const { id, init } = await startMessage(process);
200
- const worker = createHost<P>({ address: Session({ id }), principal: { kind: "worker", session: id }, onError });
201
- worker.connect(ipcLink(process), { principal: { kind: "server" }, trusted: true }, ctx); // stores may reference server types
202
- await worker.load([{ name: "@app/core", facet: coreWorkerFacet(init) }, ...workerPlugins], ctx); // serves SessionInfo
203
- await (await worker.get(Harness, {}, ctx)).resume(ctx); // tasks run only after every plugin loaded
204
-
205
- // a browser tab
206
- const tab = createHost<P>({ onError });
207
- await tab.load(webPlugins, ctx);
208
- tab.connect(webSocketLink(new WebSocket("/chord")), { principal: { kind: "server" } }, ctx);
209
- const notes = await tab.get(Notes, { session: "S1" }, ctx); // tab → server → route(Session) → worker
210
- ```
211
-
212
- ```ts
213
- // a test: everything in one process
214
- server.route(Session, {
215
- authorize: () => true,
216
- resolve: async (address) => {
217
- const [up, down] = memoryLinkPair();
218
- const principal = { kind: "worker", session: address.params.id } as const;
219
- const worker = createHost<P>({ address, principal, onError });
220
- worker.connect(up, { principal: { kind: "server" } }, ctx); // W6: connect, load, resume
221
- void worker.load([{ name: "@app/core", facet: coreWorkerFacet({ id: address.params.id }) }, ...workerPlugins], ctx);
222
- return { link: down, principal };
223
- },
224
- });
225
- ```
226
-
227
- Do not pass `context.abortSignal` to `fork`: `host.close` aborts it, which kills the worker and makes Node emit an
228
- `error` event that crashes an app without a handler. Chord closes the link at `host.close`; the worker exits when its
229
- parent link closes. `resolve` returns the link before the worker has loaded (the worker connects first, W6): made
230
- later, the link would leave the worker's `hello` unread and the heartbeat would close it during a long `load` (slice
231
- 10's spec review; the deadlock once feared here does not happen: 7a's barrier ends its first pass on a wait on another
232
- host). The workers component (§23) does this.
233
-
234
- | Call | Meaning |
235
- | --- | --- |
236
- | `createHost<P>({ address?, principal?, ...options })` | with an address: addressable, serves only objects placed there, acts as `principal` on its own host; without: a client. `P` is the app's principal type |
237
- | `load([{ name, facet }], context)` | facets with their plugin names (the plugin's `package.json` name, npm style; duplicates and invalid names are refused); runs every facet's setup, publishes all of them in one batch (types and registries served, registries composed once, contributions; requests waiting for the publication are placed after it), then waits for the start barrier (section 21: the first outcomes of its host-lifetime objects, slice 7a); a plugin whose setup throws is left out and reported (`load` resolves with `{ failed: [{ plugin, error }] }`, decision "Per plugin at startup and reload"); runs once. Loaders are adapters; base code passes its core facet the same way |
238
- | `reload([{ name, facet }], context)` | the complete new plugin set after `load` (a facet passed as the same object is an unchanged plugin): staging, then one commit, then every object of a changed or removed plugin takes its fate; resolves with a report (a plugin whose new code fails keeps its old code, listed in `failed`); one at a time (section 21, slice 7b) |
239
- | `connect(link, { principal, trusted?, codec? }, context)` | the link to the parent, at most one open; once it closed (a drop), `connect` takes the next, and every remote reference over the parent is held again on it. `principal` = who the parent is |
240
- | `accept(link, { principal, trusted?, codec? }, context)` | a link from a child; holds and calls on it act as `principal` |
241
- | `route(Kind, { authorize, resolve }, context)` | how to reach hosts of a kind (below); called before `load`, once per kind; work arriving on its links runs under `context`; returns a `RouteHandle`: `retry(address)` resolves the address again (D10b), `suspend(address)` stops resolving it until `retry` (R1) |
242
- | `get(Type, params, context, { readyTimeout? })` | a reference once its object is live, waiting through `loading`, `failed { transient }` and `failed { waiting }` up to its `readyTimeout` (section 7) |
243
- | `hold(Type, params, context, { readyTimeout? })` | a reference at once that follows its object until released (section 7) |
244
- | `close(context)` | closes the links (children, routes, then the parent), then ends every object at once and tears them down, the last to go live first (reason `close`); rejects with an `AggregateError` of the native closes that threw |
245
- | `revoke(r, context)` | revocation (section 4; slice 4b) |
246
- | `root(fn, context, { principal? })` | a call scope for code outside objects (a Durable hook, a CLI, an HTTP request): `fn` gets a handler's `ctx`, sealed when `fn` settles, `context` aborts or the host closes (slice 8 D3, section 8); an omitted `principal` acts as the host, an explicit `undefined` runs anonymous (slice 10) |
247
- | `registry(R, context, { readyTimeout? })` | registry `R`'s composed value for code outside objects once it is usable; waits for the publication, then while it has none up to its `readyTimeout`, then rejects with the last error (slice 8, 7a, section 17) |
248
-
249
- **Options of `createHost`:** `address`, `principal`, `principalKey` (section 4; the same function on every host),
250
- `telemetry` (section 29), `onError`, `closeTimeout`, `readyTimeout`, `heartbeat: { ping?, close? }`; later `revokedBy`
251
- (section 4, slice 4b) and `store` (section 10, slice 6a: the store, opened by the app with `openStore(backend, ctx)`
252
- and closed by the app with `store.close(ctx)` after `host.close`; the host never closes it). **`onError`** receives everything that fails in the
253
- background, as a tagged `HostError`: `listener_error` (a watch listener threw), `delivery_failed` (a frame delivery
254
- threw), `activation_failed { object, failure }`, `close_failed { object, native, error }`, `close_timeout { object,
255
- native }`, `drain_timeout { object }`, `protocol_error { error }`, `resolve_failed { address, error }`; later routine
256
- errors (slice 5), `derive_failed { object, member?, error }` (a derive's compute threw, once per failure episode, slice 6a), the registries' `registry_conflict { registry, message, plugins }`, `registry_failed { registry, error }`, `contribution_failed { registry, plugin, type?, error }` and `contribution_refused { registry, plugin, type?, version }` (each once per episode, slice 8), `object_failed { object, failure }` (a live object failing, slice 6a, `broken`; `transient` when a `self.follow` source failed, slice 6b R4; `failure` where the value is a `FailureCause`, `error` otherwise, 2026-10-27), `job_interrupted { object, job, id, restarts }` (a persisted run ended at the restart limit, slice 6b D6), `parked_long { object, waitingFor, state, since }` (an attempt parked longer than its `readyTimeout`, whatever its blocker, once per parking episode: a diagnostic of a ring across hosts started at the same moment or a long wait, slice 7a, audit A11, §6) and `storage_failed { error }`
257
- (slice 6a), which every app must handle: Chord never ends the process,
258
- the app exits with its own code for its supervisor or reopens.
259
-
260
- **Timeouts** are host options; no fixed numbers in the code. Two host timeouts (C13, owner, 2026-10-22):
261
-
262
- | Timeout | Bounds | Host default | Override |
263
- | --- | --- | --- | --- |
264
- | `closeTimeout` | a native's `close` (then reported as a possible leak; the rest continues); the drain of an ending object's running handlers (callers are rejected at once) | 30 s | per native: `self.open(open, close, { closeTimeout })` |
265
- | `readyTimeout` | an activation attempt's own steps (its wait for the previous instance's teardown included; paused while the attempt is parked on its dependencies, slice 7a); a getter's whole wait; how long a call made while its reference is loading waits (the park deadline) | 60 s | per `get`/`hold`/`registry`: `{ readyTimeout }` |
266
-
267
- The park deadline's per-type override is not built (only if a real case needs it). Timeouts of later slices belong to
268
- their mechanisms: the routine handover uses `closeTimeout`, a job `finish` backs off 1 s to 60 s, provider-side
269
- `linger` is per type; a reload has no install timeout (it takes the app's context, slice 7b); a per-type drain
270
- override only if a case needs it (section 26). A route's `resolve` is bounded by the app.
271
-
272
- - **Incarnations** are minted by Chord (uuidv7, code copied from pi-ai, no dependency), never passed in, and carried
273
- in the link handshake (`hello`): the other side sees a restart as a new incarnation of the same identity;
274
- references to it re-hold.
275
- - **Entry points vary** (loopback or tunnel WebSocket servers, Radius dialing out and delivering channels, a DO edge,
276
- memory), so the kernel has no `listen`; each entry point authenticates and calls `accept`. Radius no longer needs to
277
- pose as a loopback request with a secret header.
278
- - **App code, not Chord:** starting processes, init data, authentication, keep-alive decisions. Helpers come only when
279
- apps repeat the same code.
280
- - Compared with today's Chord: same shape (`createHost`, `connect`, `accept`, `route`, `load`); gone are string host
281
- names and prefix parsing, app-managed generations, the duplicate `upstream` option, `opaque` runtime objects and the
282
- loader inside the kernel.
283
- - **Worker keep-alive** works as in p2: the worker counts, the app's supervisor decides. **`host.activity`** (slice 4b;
284
- owner, 2026-10-24) is a JSON `Watchable` of `{ references, calls, jobs, lingering }`: holds arriving over links,
285
- method calls running on this host, running jobs, provider-side lingering objects. Counters are kept where the work
286
- happens; a change marks it dirty and it is published at most once per microtask turn with changes. A hold placed
287
- here counts from its arrival to its end, bound or not (one waiting for a missing provider keeps the worker alive;
288
- slice 7a); a hold this host relays counts at its destination; `host.references` lists bound references only. Core code
289
- reports it plus Durable tasks (the core `Harness`); the server's supervisor stops the worker when all are zero for
290
- the idle time (p2: 5 minutes, checked every second). Chord provides the counts, no idle logic.
291
-
292
- ### Routes
293
-
294
- ```ts
295
- host.route(Session, {
296
- authorize(principal: P, address: Address<typeof Session>): boolean;
297
- resolve(address: Address<typeof Session>, context: Context):
298
- Promise<{ link: Link; principal: P; trusted?: boolean; codec?: Codec }>;
299
- });
300
- ```
301
-
302
- - **`authorize`** runs for every hold routed over the route, with the hold's principal (section 4), before anything
303
- starts; `false` fails the hold broken `forbidden`.
304
- - **`resolve`** runs at most once at a time per address: the first hold starts it, later holds wait for the same
305
- link. The returned principal is stamped on that link; `trusted` and `codec` as for `accept`. Its `context` is
306
- aborted only when the host closes; a link it returns after that is closed at once. A `resolve` whose holds were all
307
- released meanwhile finishes and its link is kept (a worker start that produced a link finishes even if its first
308
- requester left). A `resolve` that never settles is the app's (it bounds its own `fork`); getters still time out.
309
- - **Failure and re-resolve** (slice 10 R2, owner, 2026-10-30; replaces the per-address backoff): a route has no
310
- timer. A rejected `resolve` (reported `resolve_failed`) or a returned link already closed fails the route's holders
311
- with its error (`failed`, not an endless `loading`); the route resolves again only for a new hold, on
312
- `RouteHandle.retry(address)`, or once after the address's link dropped while holds exist (a drop of a healthy link
313
- recovers at once; whether a crashed worker comes back is the `resolve`'s answer). `RouteHandle.suspend(address)`
314
- (R1) stops resolving an address (its holders stay `loading`) until `retry`. A network route that wants to reconnect
315
- keeps its own policy in its `resolve`. The workers component answers a failed address's `resolve` with its stored
316
- failure at once: workers never restart by themselves (§23).
317
- - Chord closes a route link itself only at `host.close`, on the heartbeat and on a protocol error; stopping idle
318
- workers is the app's (`host.activity`, the workers component, §23).
319
- - Work arriving on a route's links runs under the context given to `host.route(Kind, options, context)` (slice 4b).
320
-
321
- ### Links
322
-
323
- - **A link is delivery only:** an ordered, bidirectional channel of `Uint8Array` messages; adapters only move bytes
324
- and close both ends. Session recovery is the adapter's policy. Implementations (slices 3a, 4a):
325
- - `memoryLinkPair()`: delivers with `queueMicrotask` (no Node APIs); closing one end closes the peer a microtask
326
- later.
327
- - `ipcLink(port)` over a Node IPC channel (`fork` with `serialization: "advanced"`, or `process` in the child),
328
- typed structurally (no Node import in Chord). A `Uint8Array` crosses as one message; other messages on the
329
- channel (the app's start message) are skipped. It listens from the moment it is made and queues until its
330
- listener is set. `send` returning `false` is backpressure, not failure; a thrown `send`, an error callback or
331
- `disconnect` closes the link once; listeners are removed on close.
332
- - `webSocketLink(socket)` over a WebSocket (`ws` in Node, the browser's), typed structurally: one binary frame per
333
- message, `binaryType = "arraybuffer"`; messages sent while the socket connects are buffered until `open`; a socket
334
- closing or closed already gives a closed link; `close`, `error` and a text frame close it. The transport's
335
- `maxPayload` stays its hard cap (code 1009 closes the connection).
336
- - **One link object per link carries both directions** (slice 4a): the channel (handshake, codec, checks,
337
- heartbeat), a **provider side per origin** (holds and calls the peer sent, its own or those of a relay's downstream
338
- link, by the peer's ids) and a **consumer side** (holds and calls this host's own references sent, by its own
339
- counters). Message kinds are directional, so each goes to its side. A link carries nothing until a hold or call
340
- (W6).
341
- - **Roles:** `parent` (made by `connect`), `child` (`accept`), `route` (`resolve`). The role decides whose principal a
342
- hold acts as (section 4). **Trusted links** are an explicit option (`trusted: true` on `accept`, `connect` and in
343
- `resolve`'s result; default untrusted; never inferred from the link kind; owner, 2026-10-23): they skip only the
344
- `MESSAGE` schema check; framing, the codec's decode, `checkParams`, `checkArgs` and Delta decoding still run. Trust
345
- never grants the principal fields (they are read only on the parent link).
346
- - **Remote objects belong to a path:** the parent, or a route address. Each new link of a path holds every remote
347
- object of that path again (with new hold ids); a closed link drops its tables and the objects go `loading`.
348
- - **Heartbeat on every link kind, in the protocol layer** (owner, 2026-10-23): each link keeps a `lastReceived`
349
- timestamp (every received message; sends do not count); the host runs one interval timer for all its links (none per
350
- message). A link silent for 15 s sends `ping` (after its handshake); the peer answers `pong` at once, never queued
351
- behind the window. A link silent for 30 s, the handshake included, is closed (its references go `loading`). Both
352
- numbers are host options (`heartbeat`). The heartbeat detects a silent transport (TCP does not notice a sleeping
353
- laptop), not a peer that answers pings but withholds acks (bounded by the window and the pending cap instead). A
354
- handler that blocks the event loop longer than 30 s gets its links closed (documented).
355
- - **Flow control: an ack-clocked window per origin** (owner, 2026-10-23; per origin 2026-10-24). Per (link, origin), at
356
- most **K = 2** of the provider's own `bound` and `state` messages are unacknowledged; only these two kinds count
357
- (everything else is control, never queued behind them). The consumer sends `ack` (with the message's origin) after
358
- applying each, after its batch; an `ack` crossing nothing in flight is ignored. While the window is full:
359
- - each touched hold member keeps its ops in its **pending queue** (section 11: raw, never mutated, folded through
360
- the leaf index, at most 10,000 ops, then only "replace with the current value"); when an `ack` frees a slot, one
361
- `state` message carries every waiting hold's entry, its members' pending ops encoded once (or `[["r", value]]`
362
- after an overflow), all reflecting the latest commit, still atomic for the consumer. So a slow consumer gets
363
- coarser updates, never stale ones (measured: a `bufferedAmount` cap alone left state 9.4 s old behind kernel and
364
- proxy buffers; acks kept it 0.0 s old);
365
- - a hold that binds waits for a slot; its snapshot and subscription are taken in one synchronous step when its
366
- `bound` is sent; bindings and waiting state take turns when both wait, so neither starves;
367
- - a hold whose object leaves `live` while its `bound` waits goes back to pending (D1, owner, 2026-10-24; built in
368
- slice 7b with the reload, which makes a live object leave `live`); so does a bound one, unbound (§7, §22).
369
- Not built, by decision: a byte window, credit messages, snapshot admission or debt, an adapter `backlog()` API,
370
- `reset` from anyone.
371
- - **Calls: a call window N** (default 256, the same on every host) announced in `hello`: how many concurrent calls a
372
- side accepts **per origin**. A side sends no call before the peer's `hello`. A host sends at most N of its own calls
373
- per link in flight; further calls wait in the link's **call queue**, one FIFO, sent in order as replies free slots;
374
- nothing is refused for being "too many" (K16). A slot is freed once per call: by its `result` or `error`, its
375
- `abort` (when sent, at the caller; when received, at the provider), its hold's `release`, `gone`, its origin's
376
- `closed` or the link closing. A call still queued when its hold rebinds (`loading`) is rejected `unavailable` (it may
377
- name a method of the old variant). A provider seeing more than N running calls of one origin closes the link
378
- (protocol error); a call naming a hold it does not know is ignored before it is counted (Q1). A per-link N, if ever
379
- needed, must bound a relay's forwarding too.
380
- - Holds are not limited by count (authorization and params checks protect them); size limits are a separate check
381
- (section 22). Byte-heavy traffic (terminals) uses separate channels (section 23), so a large state message never
382
- holds up keystrokes.
383
-
384
- ### Relays (slice 4a; decision "Relay flow control per origin", owner, 2026-10-24)
385
-
386
- A host that receives a hold it cannot serve (the table above: a route or the parent) **relays** it: it holds
387
- it again on that link (upstream) with the arriving hold's principal and incarnation, and forwards between the two
388
- without parsing payloads. The provider keeps the window, the pending queues and the calls per origin; the relay never
389
- drops, folds or resets.
390
-
391
- - **Origins:** the relay gives each downstream origin (a downstream link, and the origin its messages carry when that
392
- link is itself a relay's) a number, one counter per host, never reused; 0 is a host's own work. Every message
393
- upstream for that origin carries `origin`; the provider keys holds, calls, windows and acks by (link, origin, id), and
394
- its answers carry the origin back. `origin` is read only on parent and route links, where a relay's messages
395
- arrive (a worker may relay a child's hold to its parent); on a child link it is a protocol error (decision "Origins
396
- only from relays", 2026-10-31); a per-origin record goes once it has no holds, calls or messages in flight;
397
- principals and incarnations stay parent-only.
398
- - **Ids are not renumbered:** an upstream hold has the downstream hold's id under the origin's number; calls the same.
399
- Two tabs (two holds) of one principal are two upstream holds, each with its own encoders (R1).
400
- - **Nothing is parsed:** the relay routes by the hold's address and authorizes it; params, arguments, results,
401
- snapshots and ops travel as opaque parts. Cost per message: decode the envelope, swap the origin, encode the
402
- envelope; parts copied once into the outgoing buffer.
403
- - **What the relay keeps:** per relayed hold, its upstream link and its original `hold` message (params copied once),
404
- which routes `call`, `abort`, `retry` and `release` upstream at once and holds again on the next link; per
405
- downstream origin, the FIFO of the sender of each `bound`/`state` message in flight and the set of upstream links it
406
- relayed to.
407
- - **Forwarding up:** `hold`, `call`, `abort`, `retry`, `release` with the origin's number; a hold waiting for its
408
- route is sent when the link exists; a `release` before that drops it. A call is forwarded at once; with no upstream
409
- link it is answered `unavailable` (it crossed the `loading` notice). Each downstream consumer is bounded by its own
410
- N, so the upstream sees at most N per origin.
411
- - **Forwarding down:** a message from upstream with an origin goes to that origin's provider side, which forwards it
412
- with its own origin (none for a tab), ids and parts unchanged. **A link answers only for what was relayed over it**
413
- (owner, 2026-10-24): every entry of a `bound` or `state`, every `failed`, `loading` and `gone` by its hold, every
414
- `result` and `error` by its call is checked against the relay's table; an answer for a hold or call not relayed over
415
- the link it came from is dropped (Q1: also one crossing a release). A `bound` or `state` left with some entries is
416
- forwarded with those; left with none, it is acknowledged to that link at once. A message for an origin from a link
417
- the origin relayed nothing to is ignored whole.
418
- - **Acks:** the relay forwards each upstream `bound`/`state` at once and returns its `ack` to the upstream link that
419
- sent it when the downstream acknowledges it (the senders FIFO). A tab served by W workers may have 2W messages in
420
- flight (plus the relay's own 2), each worker's window bounding its own. A slow tab stalls only its origin at each
421
- worker; other tabs are other origins. Measured: a slow tab through the relay catches up like a direct one (a 60 s
422
- stall: 0.38 s, 23.7 KiB at 64 KiB/s; before the rework, 24 s and three full snapshots).
423
- - **Upstream drop:** the relay sends `loading { hold }` downstream for every relayed hold on the dropped link, fails
424
- their relayed calls in flight `unavailable` (never resent), re-resolves and holds again upstream from the kept
425
- message (same id, same origin); the new `bound` is forwarded. Acks for messages of the dropped link still in flight
426
- downstream go nowhere.
427
- - **Downstream drop:** the origin's provider side ends: its served holds are released, its relayed holds forgotten,
428
- and every upstream link it relayed to gets one `closed { origin }`, which releases the origin's holds and aborts its
429
- calls there; the origin's number is never used again; messages crossing it are dropped.
430
- - **`gone`** from upstream is forwarded; the relayed hold is forgotten. Relays never make a `gone`.
431
-
432
- ### Recovery
433
-
434
- - After a drop the consumer re-holds every hold of the path over the new link and receives snapshots (a `bound` on a
435
- bound hold replaces its replicas in one batch, another variant allowed); calls in flight fail like on a disconnect;
436
- calls made meanwhile park (section 7).
437
- - A slow connection never ends an object: nothing releases a hold for falling behind (the reference count is unchanged).
438
- - A link drop is a departure (section 19).
439
-
440
- ### Values
441
-
442
- - **JSON plus `Uint8Array` leaves**, with a bytes schema type, defined independently of the transport. Every link
443
- carries the same `Message` through its codec (section 22); parts are encoded at their origin; byte segments travel
444
- raw, never base64. Same-host calls (no link) pass values by reference.
445
- - Schemas are plain JSON Schema built with `@earendil-works/pi-schema` (decision "The schema switch") and must
446
- describe data (no callbacks, no native types, no runtime codecs); `format` is an annotation, never checked. Method arguments are
447
- validated at the provider for every caller against closed schemas (section 5, R7, Q12, Q15); results and state are
448
- never validated (section 30). Values are immutable by convention once handed over (Delta's rule): nobody mutates a
449
- value it got, and nothing is copied or frozen to enforce it. There is no development mode (R9): one behavior
450
- everywhere.
451
-
452
- ---
453
-
454
- ## 4. Principals
455
-
456
- - The app defines its principal type `P`: JSON, every variant with a `kind`, a type alias (not an interface),
457
- unversioned (owner, 2026-10-22): Chord never persists principals, base code changes every host at once, links stamp
458
- them. Objects persist a projection with its own schema, never the principal (p2: chat's `Author { kind, id, name }`).
459
- p2/p3: `owner` (`access: "local" | "relay" | "device"`), `guest` (`session`, `mode`, grant revision), `server`,
460
- `worker` (`session`).
461
- - **Links stamp principals.** A caller's own data never sets its principal.
462
- - **The principal key** maps a principal to its object identity (`principalKey`, default canonical JSON; cached per
463
- principal object; the same function on every host). It should include connection provenance and grant revision, so
464
- a revoked grant's objects are distinct from a new grant's **(carried over)**.
465
- - **Principals on holds** (slice 4a; owner, 2026-10-23): a `hold` carries `principal?` and `incarnation?`. The receiver
466
- uses them **only on its parent link**; everywhere else they are ignored and the link's principal and peer
467
- incarnation apply (a tab cannot claim to be the owner; a relay overwrites what a client sent). Calls carry neither: a
468
- call runs as its hold's principal and with its hold's incarnation (refines R1/Q13, which stamped calls too). What a
469
- host sends in those fields when it holds over a route link (towards a child that honours them):
470
-
471
- | The reference was made by | `principal` | `incarnation` |
472
- | --- | --- | --- |
473
- | `host.get` / `host.hold` | the host's own | this host's |
474
- | `ctx.get` in a handler | the handler's `ctx.principal` (the caller's) | the handler's `ctx.incarnation` |
475
- | `self.get` in a remote object | that object's principal | this host's |
476
- | `self.get` in a local object or a facet | the host's own | this host's |
477
- | a relayed hold | the arriving hold's principal | the arriving hold's incarnation |
478
-
479
- So a guest's call on the server whose handler `ctx.get`s a worker type reaches the worker as the guest and gets the
480
- guest's variant; two references with different principals are two remote objects.
481
- - **Upward is a boundary:** a worker's hold of a server type goes over its parent link, and the server ignores
482
- principal fields from a child, so it acts as the worker, whoever the worker's handler serves. A worker that acts for
483
- a user towards the server passes the user as data and the server object decides.
484
- - **The caller's incarnation** (R20, Q13): `ctx.incarnation` is the incarnation of the host where the call started
485
- (from the handshake, or from the hold's field on a parent link), next to `ctx.principal`, not part of the principal
486
- or its key, never sent as data by apps; it is this host's own for local calls (section 25 uses it as a fence).
487
- - **Revocation** (slice 4b) is a typed app function, not field matching:
488
-
489
- ```ts
490
- type Revocation = { grant: string } | { device: string } | { session: string };
491
- const server = createHost<P, Revocation>({
492
- address: Server(), principal: { kind: "server" }, onError,
493
- revokedBy: (p): Revocation[] =>
494
- p.kind === "guest" ? [{ grant: p.grant }, { session: p.session }]
495
- : p.kind === "owner" && p.access === "device" ? [{ device: p.device }]
496
- : [],
497
- });
498
- server.revoke({ grant: "g1" }, ctx);
499
- ```
500
-
501
- `host.revoke(r)` ends every object and closes every child link whose principal `p` has `r` in `revokedBy(p)` (compared by
502
- canonical JSON of each value `revokedBy` returns, computed once per principal; never the host's own principal), and propagates `r` to the children as a `revoke` message on its route links,
503
- honoured only on a child's parent link, where each applies its own `revokedBy` (the same app code; nothing is
504
- replayed to a child connected later). Holders of a revoked object get `gone` with `forbidden/revoked` (owner,
505
- 2026-10-24: a reason of its own, so a UI can say "access revoked"); holds still waiting for `load` are ended too.
506
- Order: the `revoke` message goes out on the route links before the revoked child links close, so a worker's objects
507
- end `forbidden/revoked`, not `released` by the tab's `closed`. Revocation ends a principal's objects at
508
- once, whatever references or jobs remain (R11); their jobs get the abort signal and the normal `closeTimeout`.
509
- There is no re-stamping: a changed grant (mode `write` → `read`) is a revocation of the old one; the client
510
- reconnects and authenticates anew, and its references re-hold. Reconnecting never restores revoked authority. Work
511
- started on behalf of a revoked principal in a shared store stops when its reconciling routine runs (R10's window,
512
- accepted; section 25); there is no revocation hook.
513
- - `local` objects have no principal in their identity; their handlers and references act as the host (section 5).
514
-
515
- ---
516
-
517
- ## 5. Object types
518
-
519
- ```ts
520
- export const Notes = remote("notes", { version, hostAddress, params, variants });
521
- export const NoteStore = local("notes.store", { version, params, members });
522
- ```
523
-
524
- | | `remote` | `local` |
525
- | --- | --- | --- |
526
- | reachable from | any host, across links | its own host only |
527
- | identity | (type, params, principal key) | (type, params) |
528
- | principals, variants | yes | no |
529
- | factory | `(params, principal, self)` returning `{ variant, members }` | `(params, self)` returning the members |
530
- | arguments | validated once at the provider for every caller (compiled closed schema, R7, Q12); unknown fields rejected; passed by reference on the same host | validated the same way (Q15), never copied |
531
- | results | not validated; passed by reference on the same host | not validated, not copied |
532
- | members | state (JSON) and methods (JSON plus bytes) | plain-data state and methods; no `opaque`, no callbacks |
533
- | `ctx.principal` in methods | the caller | the host's principal (none on a client); references a local object makes act as the host |
534
-
535
- ```ts
536
- variants: {
537
- editor: { state: { notes: NotesSchema }, methods: { add: method(AddArgs, NoteId), remove: method(RemoveArgs) } },
538
- reader: { state: { notes: PublicNotesSchema } },
539
- },
540
- // the factory chooses one variant per object (slice 3a, C15):
541
- host.serve(Notes, ({ session }, principal, self) =>
542
- principal.kind === "owner" ? { variant: "editor", members: { notes, add, remove } } : { variant: "reader", members: { notes: publicNotes } });
543
- ```
544
-
545
- - **Names** (owner, 2026-10-27): object type names, host kind names, document (`defineState`) and job (`defineJob`)
546
- names use `[a-z0-9@/._~-]`, lowercase, checked at declaration (they become SQL table names in the store, joined with `:`).
547
- - **Keyed state members** (owner, 2026-10-26; `local` contracts only): `members: { notes: keyed(NoteSchema) }`; the
548
- provider returns a keyed document handle; a consumer on the same host takes `ref.notes.at(key)` in its factory (a
549
- counted pin: the key stays loaded while the consumer lives) or `ref.notes.watch(key, ctx)`/`get(key, ctx)` anywhere;
550
- an absent key reads `initial()`, a retirement arrives as the `retired` flag (a derive over it carries the flag on).
551
- Across links, a view per entity (`NoteView { session, id }`) is held as an ordinary remote object.
552
- - **Methods:** `method()` (no arguments, no result), `method(args)`, `method(args, result)`, `method(undefined,
553
- result)`. A method without arguments omits them in the API (`ref.bump(ctx)`, implemented as `bump: async (ctx) =>
554
- …`); `null` is their internal and wire form (owner, 2026-10-22).
555
- - **Implementations** (owner, 2026-10-22): a state member is a JSON `Watchable` the factory returns (a document handle,
556
- a derive, a reference member, `constant(...)`), never a getter; a method is a function `(args, ctx)` or `(ctx)`.
557
- Activation checks what the factory returned (plugin code): exactly the variant's members, methods as functions,
558
- state members as JSON watchables (a `NativeWatchable` or anything else fails the object `broken` naming the member,
559
- Q14).
560
- - **Reserved member names:** `then`, `release`, `state`, `retry` and `variant` are refused at declaration (a reference
561
- has them; `then` would make an awaited reference thenable).
562
- - **Compatibility (strict, like documents; R6):** a hold carries only the consumer's contract `version` and
563
- fingerprint, never a description. The provider binds when both equal its current ones, or (slice 7b) when the
564
- version is one it accepts and the fingerprint equals the one computed from its own history (section 27). Every
565
- contract change, additive ones included, bumps `version`. Anything else leaves the request unbound `version`:
566
- `failed { waiting }` with `contract_mismatch` (slice 7a: not the consumer's fault; a publication that fits wakes it,
567
- §3). The fingerprint covers params, variants and members, not the host address. A consumer whose contract does not
568
- fit waits on its own request; the provider object and its other bindings are not affected.
569
- - **Variants:** a member name has the same kind (state or method) in every variant that has it, and a method the same
570
- signature (arguments and result) in every variant; state schemas may differ per variant (redaction). Enforced at
571
- the type level in `remote(...)` and at declaration at runtime. A remote factory returns one variant, `{ variant,
572
- members }`; `ref.variant` is the discriminant (section 7). Calls are checked against the binding's variant
573
- (`invalid/member` outside it).
574
- - **Params** (owner, 2026-10-21/22): a flat record of required fields, each `str()`, `int()`, `bool()` or `oneOf(...)`
575
- of string literals, constraints allowed (`str({ pattern })`, `int({ min: 0 })`); no defaults, optional, nested or
576
- unknown fields. Checked for every caller with one compiled closed-object pi-schema check (a missing or extra field
577
- fails `invalid/params`). The identity key is the field values in declared order, each escaped, joined with `|`.
578
- Params are never copied or frozen: the object keeps the caller's object, immutable by convention.
579
- - **Arguments (R7, Q12, Q15):** always validated with the provider's schema, whoever the caller is (trusted code is
580
- not type-checked code: plugins are bundled without type checks), never with a schema a peer sent; object schemas are
581
- closed (`obj()` sets `additionalProperties: false`), so an unknown field fails `invalid/args` instead of being
582
- stripped; nothing is copied or mutated; arguments have no defaults (optional fields are `opt()`, handlers write
583
- `args.limit ?? 50`). Same-host arguments are not checked for plain data (no prototype or getter checks): callers pass
584
- plain data by convention. Provider schemas compile lazily at first use, cached in `WeakMap`s keyed by the schema
585
- owner; accepted versions' validators also on first use. Bytes are leaves (`instanceof Uint8Array`, optional length
586
- bound), never walked. Results and state are not validated.
587
- - **Providers** (`bindProvider(Type, accepts)`, L1): runs `checkAccepts` once per load and reload and keeps the
588
- validated mappings; per call `checkArgs(provider, method, raw, boundVersion, context)` returns a tagged value,
589
- `{ kind: "method"; args; result? }` (current-shape arguments and, for an old-version caller, the result mapping back)
590
- or `{ kind: "call"; args; call }` (the provider's own replacement of a removed method, invoked by Chord, slice 7b). The
591
- binding is held only by the served type's registration and by calls in flight (GC-tested; no global strong cache).
592
- - **Errors** (L1, slice 3a): `ChordError` with a code and, for some codes, a reason, a closed union that is part of the
593
- link protocol (adding one bumps the protocol version; a receiver rejects unknown reasons; a test pins the list):
594
- `invalid` (`args`, `params`, `member`, `host_address`, `reentrant`, `read_after_bulk`, `cycle`), `contract_mismatch`
595
- (`updating`), `forbidden` (`revoked`), `gone`, `not_ready`, `released` (`ended`, `closed`, `settled`, `version`, `discarded`; none for a holder's own release), `too_large` (`part`), `unavailable` (`locked`,
596
- `park_timeout`, `busy`, `storage_failed`, `undeclared`: a registry no plugin serves here, slice 8), `aborted`. A failed check names pi-schema's JSON Pointer path ("unknown field", "missing", else
597
- pi-schema's message; `~` and `/` in keys escaped as `~0`, `~1`). Plugins throw `PluginError(code, message,
598
- details?)` for codes of their own; anything else crosses a link as the plugin code `internal` with its message, never
599
- a stack or a cause; plugin errors never use Chord's codes. An error rebuilt from the wire is not copied and only its
600
- envelope is checked; a malformed envelope is a protocol error.
601
- - **Methods return data,** never objects; an object is handed out as its address and the receiver does `ctx.get`.
602
- - **No callbacks as arguments,** on either kind: behaviour goes through registries, multi-step work through jobs,
603
- input through flows, runtime services through core objects. Real schemas instead of `Type.Unsafe`.
604
-
605
- ---
606
-
607
- ## 6. Objects
608
-
609
- ### Lifecycle
610
-
611
- ```
612
- (get) → activating (parked on its dependencies → own steps) → live → ending → ended
613
- └→ failed (backoff) → activating …
614
- live → failed (a runtime failure of the owner, slice 6a: broken, by reload or retry only)
615
- ```
616
-
617
- - **One object per identity.** The first `get` runs the factory; later gets share the object.
618
- - **Lifetime follows from kind and params (Q-A, owner, 2026-10-21):** there is no `lifetime` option and no lazy flag.
619
- A `local` type with empty params lives as long as the host: started eagerly at host start, never ended by reference
620
- count (it may hold persisted data, P3, and contribute to registries, R21). Every other `local` type and every
621
- `remote` type lives while referenced (`linger` keeps it briefly after the last reference). No remote object has host
622
- lifetime: its identity includes the principal, and long-lived parts belong in a local shared store. Below,
623
- "host-lifetime object" means a `local` object with empty params. Running and finishing job runs keep their
624
- object alive as a count, not as references, while an attempt is live or activating ("Slice 6a small items" (12)); when
625
- the count reaches zero with no holders, the object ends (§15).
626
- - **Activation** (one fresh attempt each time, bounded by `readyTimeout`, its wait for the previous instance's
627
- teardown included): the factory runs; singleton documents take `initial()` and, on the object's first activation,
628
- persisted documents load and its tables' definitions are checked and migrated (slice 6a; the deadline paused during
629
- eager migration work); its requests are made (`self.get`, `self.registry`, keyed pins), and the attempt is
630
- **parked** until every one is live and hydrated (below; the deadline paused); then its own steps run under the
631
- deadline: natives open one after another, followed sources attach, the returned members are checked (section 5),
632
- derives compute; routines start (slice 5). The object goes live when all of that succeeded. Calls wait behind its
633
- **gate** until then.
634
- - **The seal fence** (owner, 2026-10-26): every attempt has a seal token (a job run invocation its own, for its state
635
- changes and outcome). After the seal, new work through the attempt's handles is refused at use (`self.tx`, `ctx.get`,
636
- a job or routine start); commits are checked when they enter the store's commit step (sealed: rejected `released`,
637
- nothing written) and at adopt (sealed during the SQL: durable, adopted into the object's documents, its staged job
638
- changes adopted into the object too: decision "Second spec review: the majority" (3)); at the seal a transaction not yet in the step is aborted and the line released, a started step
639
- finishes before teardown completes; cleanup (references, presence, activity counts) still runs. A pure swap is not a
640
- replacement.
641
- - **Ending** (slice 1, 2): new calls are rejected; every caller of a running call gets `released` at once; the
642
- handler keeps running in the background under an aborted context and its `self.tx` throws `released` (a running
643
- method can change nothing after the end). Each call runs under a context aborted by its caller and by the object's
644
- end (one controller per attempt, linked until the call settles; a caller's cancellation aborts only its own call); a
645
- call whose caller context is already aborted is rejected before its handler runs. Then the **drain** waits for the
646
- handlers' own promises, bounded by `closeTimeout` (`drain_timeout` reported), natives close in reverse order,
647
- documents are dropped, derives detached, and references released last (closes may use them). Routines stop and jobs
648
- follow their rules (slice 5).
649
- - **A live object can fail** (owner, 2026-10-26): a runtime failure of the owner (a `migrate` failing on access, a
650
- stored version newer than the code) seals the live attempt and makes the object `failed` (`broken`): calls reject
651
- with the cause, state members keep their last values, natives close, documents stay on the object; recovery by
652
- reload or `ref.retry()`; live dependents stay live. Its references keep following every member (its own and
653
- re-exposed ones) until the commits admitted before the seal adopted and published once, then take their last values
654
- (audit A10, 2026-10-30: one rule, as restarts), and a retry's factory waits for that.
655
- - **Parked on its dependencies** (dependency model §3, slice 7a; supersedes R18's dependency deadline and backoff): a
656
- dependency is what an attempt declares and needs before it goes live: `self.get` (local or remote), `self.registry`,
657
- keyed pins (`at(key)` on another object's keyed member); `self.follow` is the attempt's own step, not a dependency.
658
- While any dependency is not live (and hydrated), the attempt is parked and its object shows:
659
-
660
- | Its dependencies | The object shows |
661
- | --- | --- |
662
- | any `loading`, none failed | `loading` |
663
- | any `failed` | `failed { waiting }`, `retryAt` undefined, error `unavailable` "waiting for X: <root cause>" (X the first failed one in declaration order, the root cause found through its message's "waiting for …: "; always these two, so a ring of waiting attempts settles after one round; within 500 characters, X's label clipped first, fix round 1) |
664
- | one failed with `invalid/cycle` (a dependent off the ring) or `forbidden` (an `authorize` that refused it: authority, M§3.6) | `broken` with that error: nothing heals it but `ref.retry()` or a reload |
665
- | one `ended` (revoked, its host closed) | `broken` with that error: the request cannot come back |
666
-
667
- **Nothing times out while parked:** no dependency deadline, no backoff (only `parked_long`'s diagnostic report, below); the attempt's `readyTimeout` deadline is paused
668
- (as eager migrations pause it) and resumes with the budget left; the identity backoff stays for the object's own
669
- `transient` failures only. **Wakes:** the parked attempt checks again at every change of a dependency (live,
670
- loading, failed, a new cause compared by value, ended, and its first outcome, below), coalesced per object after the
671
- batch that caused them (a change while it checks or loads pinned keys is remembered); it never re-runs its factory.
672
- A parked attempt keeps its documents, declarations, requests and seal token, and holds no natives. **The dependency
673
- check is the boundary:** once all are live (and the pinned keys loaded), the own steps run; a dependency that leaves
674
- `live` afterwards changes nothing (R18 after live: the object goes live; its calls through that reference meet its
675
- state). **Retry passes on:** `ref.retry()` (or a `retry` message) on an object parked `failed { waiting }` passes on
676
- to its failed dependencies (audit A5, 2026-10-30): on one host one retry's walk keeps a visited set, so a diamond
677
- retries a shared dependency once; across links the `retry` message carries a hop budget (`hops`, 16 from the first
678
- host, one less per host, dropped at 0), so a waiting ring across hosts passes it round until the budget runs out
679
- (starting no attempt) and a diamond across hosts may retry a shared dependency twice (harmless). A `broken` or
680
- `transient` one starts an attempt, a parked one passes it on, a request waiting unbound in an index is left as it is
681
- (an event wakes it), a refused hold over a link re-runs its start. A `retryOn` wake while parked does nothing. When
682
- a parked object's last reference goes, it ends at once (it is not live: no `linger`) and releases its requests.
683
- `broken` is only for an object's own code, cycles and authority; no failure keeps references (the R18 retry trigger
684
- is gone: parking replaces it).
685
- - **Dependency cycles are rejected (Q5):** every object instance has a uuidv7 instance id, minted at its first
686
- attempt; an object that restarts gets a new one, so an old chain never matches (slice 4b, the first user; D4,
687
- owner, 2026-10-24). On one host, at
688
- `self.get(B)` during A's activation Chord follows the waiting edges of activating objects from B; reaching A is a
689
- cycle. Across hosts, a hold made during an activation carries the activation chain of instance ids in its header
690
- (bounded; ignored from untrusted links): the provider rejects the hold when the instance being activated is in the
691
- chain (slice 4b; on one host slice 1; at most 32 entries; locally created objects inherit the activating chain). A
692
- cycle fails the activation `broken invalid/cycle` with the cycle as cause ("A → B → A"), and every other activating
693
- object on it the same way; no references are kept. A dependency failing with `invalid/cycle` makes its dependent
694
- **broken** with the same error (owner, 2026-10-24: it would wait on a ring that never heals); dependents that are not
695
- on the cycle break too, and a reload or `ref.retry()` recovers them. The walk on one host follows the waiting edges
696
- of activating and parked attempts (exact). Checked again after a reload. Cost: O(chain) per declared reference,
697
- only during activation.
698
- **The gap: rings across hosts started at the same moment** (owner, 2026-10-29: no probe): a chain is fixed when its
699
- object is created, so a cycle entering an object already activating is not detected. Example: A on the server and B
700
- on a worker start at the same moment, A declares B and B declares A; the holds carry `[A]` and `[B]`, neither finds
701
- the other, and without a dependency deadline both stay parked. It is made visible: an attempt parked longer than its
702
- `readyTimeout`, whatever its blocker (audit A11, 2026-10-30), is reported once per parking episode as
703
- `parked_long { object, waitingFor, state, since }` (`waitingFor` the blocker's label, `state` `loading` or `failed`); nothing fails or retries. A cycle is a plugin bug; **the guide's four
704
- rules** for plugin authors and agents (host README): (1) a factory declares only what the object needs, never a type
705
- that needs it back; (2) back-references and occasional lookups go into methods and routines (`ctx.get`); (3) data
706
- flows up through state and registries, not mutual `self.get`; (4) host-lifetime objects on the server never declare
707
- worker types in their factory.
708
- - **Failed:** a broken part fails the whole object: a throwing factory, document hydration or `migrate`, a failed
709
- open, a derive that throws on its first computation during activation. After the object is live, a throwing derive
710
- fails only its own member (`broken`, W1). The cause is tagged and decided by Chord from where it failed:
711
-
712
- ```ts
713
- cause: { kind: "transient"; error: ChordError } // the object's own effect failed (an open, a follow): backoff
714
- | { kind: "broken"; error: ChordError } // its own code (factory, derive, hydration, migrate), a cycle, authority
715
- | { kind: "waiting"; error: ChordError } // not its fault (slice 7a): no provider, no fitting version, a
716
- // dependency failed; retryAt undefined, woken by an event
717
- ```
718
-
719
- Only an `open` may choose `broken` itself (`throw broken(error)`, e.g. invalid configuration). **Transient** causes
720
- get a **backoff per identity** (1 s doubling to 60 s; a map holding no object, so a failed object is collected after
721
- its last reference while its window runs; concurrent gets share one attempt; success resets). **Broken** ones are
722
- retried only by a trigger. Triggers (for both): `ref.retry()`, a plugin reload (slice 7b, §21) and wake signals the factory
723
- declares with `self.retryOn(...readables)` (slice 8; anywhere in the factory: the factory specifies, Chord installs
724
- the watches before natives open, so a failed open still has them). Every trigger works like `ref.retry()`: the
725
- backoff window is skipped, an attempt starts now, holders are told `loading`. `retryOn` sources must live independently of the
726
- attempt (registry values); a reference's member is a type error. A facet cannot fail
727
- after `load`: its setup only declares (a throwing setup leaves its plugin out of `load`, reported in `load`'s
728
- `failed`; decision "Per plugin at startup and reload"; owner, 2026-10-26, 2026-10-30).
729
-
730
- ### The factory principle
731
-
732
- ```ts
733
- host.serve(NoteStore, ({ session }, self) => {
734
- const notes = self.state(NoteDoc); // section 9
735
- const index = self.state(Index);
736
- const count = self.derive([index], ([i]) => i.ids.length); // section 12
737
- const watcher = self.open(async (context) => watch(dir, { signal: context.abortSignal }), (w) => w.close()); // section 13
738
- self.onLive(async (ctx) => { for (;;) { await sleep(HOUR, ctx); await cleanup(ctx); } }); // section 14
739
- const imports = self.job(ImportJob, { run, finish }); // section 15
740
- self.contribute(Http, { routes: { … } }); // section 17
741
- const info = self.get(SessionInfo, {}); // start data, section 18
742
- const catalog = self.get(Catalog, {}); // section 7
743
- return { index, count, add: …, startImport: … };
744
- });
745
- ```
746
-
747
- - Synchronous and declarative: no awaits, no side effects; async work happens in activation (opens), in calls, in
748
- routines and jobs.
749
- - Handles stay valid for their attempt's life (owner, 2026-10-26: documents and the line belong to the object; each
750
- attempt's handles carry its seal token and definition version); nothing is "read at use" or re-fetched.
751
- - On a reload the factory runs again: in staging against a recording `self` (declarations only), then for real; pure
752
- objects swap in place (new methods and derives, same documents), native objects restart after their drain,
753
- objects of a removed type end and their holders wait (section 21).
754
-
755
- ### Pattern: shared store, per-principal views
756
-
757
- ```
758
- NoteStore {S1} local shared store: the stored notes, once
759
- ▲ self.get ▲
760
- Notes {S1} as owner Notes {S1} as read-only guest
761
- variant "editor" variant "reader": derives a filtered view
762
- ```
763
-
764
- Heavy or shared parts (a Durable watch, a prompt watcher, a sandbox, a store) live once in a `local` shared store;
765
- per-principal `remote` views get it and expose what their principal may see. Authority is the view's; the store is
766
- trusted and acts for the host. Views of the same variant read one value from the store (a redaction is computed once,
767
- not per guest; section 12). Any plugin uses this pattern with the same primitives; base code is not special.
768
-
769
- **Worker-wide native owners:** the facet cannot `self.get` a type it serves, so an owner of a per-session native (an
770
- inbox watcher, a sandbox) is a `local` object with empty params (host lifetime) that reads its session from the core's start
771
- data (`self.get(SessionInfo, {})`, read in its opener). Paths are derived by the plugin from generic start data (the
772
- data directory), never provided per plugin.
773
- Such an object cannot `self.get` a session-scoped object in its factory (the session is known only after activation):
774
- it gets one with `ctx.get` in a routine or method (R22). A `get` with params computed after activation is added only
775
- if a real case needs it.
776
-
777
- **Natives that follow a relocation:** the native is a stable manager (`self.open` once); a routine on the session
778
- location switches its internal resource (the watched directory) and bumps a generation, so late events from the old
779
- location are dropped.
780
-
781
- ---
782
-
783
- ## 7. References
784
-
785
- | Where | API | Released |
786
- | --- | --- | --- |
787
- | a factory | `self.get(Type, params)` | when the object ends |
788
- | a call | `await ctx.get(Type, params, { readyTimeout? })` | when the handler settles |
789
- | outside | `await host.get(Type, params, context, { readyTimeout? })` / `host.hold(Type, params, context, { readyTimeout? })` | `release()` |
790
-
791
- - **`host.get`** (and `ctx.get`, `host.registry`) resolves with a reference once its object is live and **hydrated**
792
- (every state member of its variant has a value). It waits while the reference is `loading`, `failed { transient }`
793
- or `failed { waiting }`, up to its `readyTimeout` (default 60 s, the caller's choice), then rejects with the last
794
- cause; only `failed { broken }` rejects at once (owner, 2026-10-29, decision "Getters wait through `waiting`"). A
795
- getter that gives up releases its reference. **`host.hold`** returns a reference at once that follows its object
796
- until released (loading, live, failed and retried as its object is, loading again while its link is down) and never
797
- rejects; only invalid params throw (checked at once, also before `load`: design audit 7, 2026-10-27). A type not
798
- served where it goes is `loading` before the host's publication and `failed { waiting }` after it, before and after
799
- `load` alike (§3; slice 7a). Its `variant` is `undefined` until its first binding (slice 3b). A UI holds and shows
800
- `ref.state`; code that needs the object now gets it, with the patience it passes. There is no `state: false` option
801
- (C8) and no `optional` flag.
802
- - **Narrowing by variant:** `ref.variant` is the discriminant (C15: no `inVariant`/`expectVariant`); `RefIn<C, V>`
803
- narrows to some variants (strict unions, never weakened).
804
- - **References are the only indirection** (owner, 2026-10-29; supersedes 6a's member source per object and 7b's
805
- hand-over): a consumer's watches and derives over `ref.member` attach through the reference's member, which passes
806
- the subscription straight through to the object's own document or derive (no extra hop, no copy: the commit's value
807
- and ops by reference). When what the reference points at changes (a new object instance after a factory re-run:
808
- reload, retry, restart; a new object after its type was removed and served again; another variant), the reference
809
- moves its subscriptions to the new one and sends one frame, a diff from the last value (consumers' derives recompute,
810
- a failed one heals; a member the new variant lacks fails `invalid/member`). While it points at nothing, its members
811
- keep their last values (a pointer, no copy): while loading (a restart, a retry, a swap whose new instance is not live
812
- yet) its watches get no call (`ref.state` says `loading`); while failed (a live failure, its version refused, its type
813
- removed, a failed dependency) they get one `failed` call with the cause's error and stay open (decision "Failures are
814
- watch calls"); a reference that never had a value reads `not_ready` while loading and its failure's error while failed, and its
815
- watches wait for its first values. A member the new variant lacks is not a failed reference: it fails `invalid/member`
816
- (reads throw it, watches get one `failed` call) until a later variant brings it back. Keyed watches and pins
817
- re-pin on each new instance the same way (a key keeps its last value until the new instance has loaded it); a
818
- dependent's factory pin is still loaded before the dependent goes live. Once hydrated, a reference has last values for every state member of its bound variant, read or not: when it
819
- detaches it takes them at its version from the outgoing instance (through that instance's mapping for an older
820
- version), keeping no node of it. After a `failed` call, the next good value arrives as `[["r", value]]` even when
821
- unchanged; a watch opened while failed starts at the last value and gets the failure once. No source, mapping,
822
- document handle or pin of an instance outlives it through a reference: a detached reference keeps only plain last
823
- values and its failure; releasing it drops them and its bindings; stopping a keyed watch drops its pin. Derives over a failed reference member compute on its last value (a contribution built on it stays); only the
824
- member's own watches get the `failed` call, and `ref.state` shows the failure (owner, 2026-10-29). A re-exposed member is
825
- the re-exposing object's reference member, followed the same way. Over a link the same rule: the replica keeps its
826
- last values readable while its hold is failed. Nothing outlives its object instance and nothing is handed between
827
- objects.
828
- - **References across a reload** (slice 7b §6): a reference is never ended by a code change. Its object swapped in
829
- place or restarted: it follows the new instance (above; a hold over a link gets a fresh `bound`, §22). Its version no longer accepted, or a member of it refused (`contract_mismatch`): it leaves the object and waits
830
- unbound (`failed { waiting }`) with its last values; the object and its other holders stay. Its type removed: it
831
- waits unbound `not_served` with its last values; a publication that serves the name again binds it to the next
832
- object (a new object: its in-memory documents start over from `initial()`, persisted ones load again). On a removal
833
- the references take their last values at the seal: a commit admitted at that moment is stored and loaded by the next
834
- object, but not in the last values they show while they wait (accepted: deferring it would need new state on the
835
- waiting path, owner, 2026-10-29) (one frame, watches and derives heal, keyed pins re-pin, parked calls flush or reject, presence lists it
836
- again). A reference of an older version a provider accepts reads its state members through the object instance's
837
- shared mapping for its version (and keyed members per key), and its calls are mapped forwards and their results
838
- back, or run the provider's replacement of a removed method (`checkArgs`). A reference knows its version from the
839
- contract token it was made with; one made by outside code keeps the token its caller passed (Chord reloads no caller
840
- code).
841
- - **Members:** each state member of a reference is a watchable of the provider's member (a replica over a link);
842
- watches taken through a reference belong to it and end when it is released. Methods are functions (`ref.add(args,
843
- ctx)`, `ref.bump(ctx)`).
844
- - **`ref.state`** is a `NativeWatchable` (slice 3b) of a tagged value; watches get each new state:
845
-
846
- ```ts
847
- | { kind: "loading" } | { kind: "live" }
848
- | { kind: "failed"; cause: FailureCause; retryAt: number | undefined } // retryAt: a transient cause's backoff;
849
- // undefined for broken and waiting
850
- | { kind: "ended"; error: ChordError } // released by its holder, or its object ended
851
- ```
852
-
853
- | Situation | Calls | Values |
854
- | --- | --- | --- |
855
- | link drop | park until reconnect | readable (`loading`) |
856
- | object loading or restarting | park until live | readable (`loading`) |
857
- | unbound (not served, another version) or parked on a failed dependency | reject at once with the cause | `failed { waiting }` (slice 7a) |
858
- | object `failed` | reject at once with the cause | `failed` with cause and `retryAt` |
859
-
860
- - A failed reference stays alive: while held, Chord retries a `transient` failure per the backoff and wakes a
861
- `waiting` one at the event it waits for; `ref.retry()` tries at once (a Retry button; over a link the `retry
862
- { hold, hops }` message, which also re-runs a refused hold's start: the host address, binding; design audit 2026-10-27;
863
- on a parked object it passes on to the failed dependencies, §6); success goes `loading`, then `live`. A provider
864
- tells a pending hold's consumer each failure (`failed`, with the rest of its backoff window for a transient one),
865
- each new cause of an object parked on a failed dependency, and the next attempt (`loading`).
866
- - **Parked calls** (slice 3b): calls made while the reference is loading are queued in order, each waiting at most the
867
- reference's `readyTimeout` from the moment it was made (never renewed), then fail `unavailable/park_timeout`; they
868
- are sent in order when it goes live (a new call never overtakes them) and rejected with the cause when it fails.
869
- Otherwise a call ends only through its caller's signal; there is no per-call deadline.
870
- - Calls already sent when a link drops fail `unavailable` and are not resent; calls running on an instance that ends
871
- fail and are not resent. **Releasing a reference rejects the calls made through it** (`released`), locally and over
872
- links (slice 3a). A consumer receiving `gone(h)` rejects its own pending calls on `h` (Q1).
873
- - References survive link drops: one owner of a host's remote references holds them again on every new link of their
874
- path; a re-hold may bind another variant (slice 3b).
875
- - **Consumers** handle a failed call as they handle a disconnect (error shown, user retries); Chat's own submission
876
- `requestId` stays an app concern.
877
-
878
- - **Optional dependencies** are registries owned by the dependent, not optional references: ports contributes its
879
- forwards to `radius.forwards`; without ports the table is empty and radius works.
880
-
881
- - **Authority checks** live in the per-principal view's methods (and in `route.authorize` before a host starts);
882
- there is no async activation guard. An object for an address that carries authority (`LoginFlow { id }`) may exist;
883
- what a caller can see and do is decided by its view.
884
-
885
- ---
886
-
887
- ## 8. `ctx`
888
-
889
- Every handler gets a `ctx` (a `Context`): `telemetry` (the current span, section 29), `abortSignal` (the caller
890
- cancelled or the object ended; there is no per-call deadline), `principal` (the caller as its link stamped it; on a
891
- local object's handler the host's principal, none on a client), `incarnation` (the calling host's, section 4), and
892
- `get(Type, params, { readyTimeout? })` (references as the caller sees them, released when the handler settles; a
893
- `get` after that throws `released`). Later: `ctx.trace(name, attributes, fn)` gives `fn` a child `ctx` under a child
894
- span (slice 9, cut C11 to decide); in a job's `run` also `jobId` and `state` (slice 5). Pass `ctx` to everything you wait
895
- on. Code outside objects gets a `ctx` from `host.root` (slice 8). Durable's `Context` is the same module
896
- (`../context`); bridging is explicit. No code versions, no request ids.
897
-
898
- **Contexts are required** (owner, 2026-10-22): every function that takes a context requires it, as the parameter after
899
- the required ones (context last); optional only on error-reporting paths. A getter that cannot take one (a lazy derive
900
- read) uses its owner's.
901
-
902
- **Call-scoped natives** (a native that lives exactly as long as one call: a temporary SSH session for a directory
903
- listing, a file handle for a download) are opened and closed inside the method with `try/finally`; there is no
904
- `ctx.open`:
905
-
906
- ```ts
907
- list: async ({ path }, ctx) => {
908
- const session = await ssh.open(config, ctx.abortSignal);
909
- try { return await session.readDir(path, ctx.abortSignal); }
910
- finally { session.close(); }
911
- },
912
- ```
913
-
914
- ---
915
-
916
- ## 9. Documents
917
-
918
- ### Definition and handles
919
-
920
- ```ts
921
- const Settings = defineState("settings", {
922
- schema: SettingsSchema,
923
- version: 1,
924
- initial: () => ({ theme: "dark" }),
925
- persist: true, // default: in memory
926
- checkpointWhen: () => true, // required for persisted documents; small: a base per write
927
- });
928
- const Draft = defineState("draft", {
929
- schema: DraftSchema,
930
- version: 2,
931
- migrate: (old, from) => ({ body: old.text }), // pure
932
- initial: () => ({ body: "" }),
933
- keyed: true, // many per object
934
- persist: true,
935
- checkpointWhen: (value, ops, info) => info.deltasSinceBase > 50,
936
- });
937
-
938
- host.serve(DraftStore, (_, self) => { // local, empty params: may persist (P3)
939
- const settings = self.state(Settings); // THE settings document
940
- const drafts = self.state(Draft); // all Draft documents of this object
941
- return {
942
- settings, // a singleton handle is an exposable Watchable
943
- get: ({ conversation }, ctx) => drafts.get(conversation, ctx),
944
- save: ({ conversation, body }, ctx) =>
945
- self.tx(async (tx) => {
946
- const d = await tx.draft(drafts, conversation);
947
- d.body = body;
948
- return d.body.length;
949
- }, ctx),
950
- drop: ({ conversation }, ctx) => self.tx(async (tx) => tx.retire(drafts, conversation), ctx),
951
- };
952
- });
953
- ```
954
-
955
- - **Ownership:** a document belongs to exactly one object identity, and so does its line (owner, 2026-10-26: across the
956
- object's attempts, retries, failures and native restarts; an attempt keeps only its natives, routines, derives and
957
- seal token) (persisted ones across restarts; in-memory ones for
958
- the object's life, across reloads and native restarts). Facets have no documents (owner, 2026-10-26: C16).
959
- Others see it only through exposed members. References to other objects are stored as data (addresses).
960
- - **Singleton** (no `keyed`): loaded at activation, kept in memory while the object lives; `handle.value` is
961
- synchronous; the handle is an exposable `Watchable`.
962
- - **Keyed:** addressed by a short key local to the object, loaded on demand; `await handle.get(key, ctx)` reads (creates
963
- nothing); `for await (const key of handle.keys(ctx))` pages keys (both take a context, owner, 2026-10-26) (indexed per owner and definition, also in memory). No
964
- live key list: a collection shown live is a singleton (an object holding a list or map); large collections are
965
- methods returning pages.
966
- - **Values are immutable by convention** (Chord Delta's rule, as in Durable): `handle.value` and published values
967
- are shared, never mutated by their readers, and never copied or frozen; a draft belongs only to its transaction.
968
-
969
- ### Writes and transactions
970
-
971
- - **Only `tx.draft`** (as Durable's `tx.doc`): `await tx.draft(handle, key?)` inside `self.tx(fn, ctx)`
972
- returns a draft of the current document, or a draft over `initial()` if it is absent. Reading is drafting (Delta's
973
- overlay: no copy). An unchanged draft (empty ops) commits nothing, so an absent document is never stored by being
974
- read. `tx.retire(handle, key?)` removes a document. `keyed` makes the key mandatory at the type level. There is no
975
- `tx.get` for documents (tables have one, section 10).
976
- - Drafts record ops (assignment, `push`, `Object.assign`); the same document returns the same draft within one
977
- transaction. **Drafts are revoked when the transaction settles (R12, as in Durable):** a transaction writes and
978
- returns at most plain values (an id, a count), never anything taken from a draft. To return data, read after the
979
- commit from the document (`handle.value`, `handle.get`), which then holds the committed revision; a later commit
980
- may slip in between, and the reader gets that newer value.
981
- - **No existence check inside a transaction (R13, as in Durable):** `tx.retire` of an absent document is a no-op (it
982
- never creates); `tx.draft(handle, key)` creates a missing document when the draft changes;
983
- whether a keyed document exists is read outside the transaction (`handle.get(key, ctx)` gives `undefined` for an absent
984
- one). **A singleton always has a value (Q11):** `handle.value` is the written value or `initial()`, never
985
- `undefined`, so an exposed singleton is typed `T`; singleton existence has no API (unlike Durable's `snapshot()`).
986
-
987
- Patterns:
988
-
989
- ```ts
990
- // Return data: write in the transaction, read after the commit.
991
- await self.tx(async (tx) => { (await tx.draft(notes)).items.push(note); }, ctx);
992
- return notes.value.items; // the committed revision (or a newer one)
993
-
994
- // Remove if present: retire is a no-op for an absent document.
995
- await self.tx((tx) => tx.retire(drafts, conversation), ctx);
996
-
997
- // Create if missing: the draft creates it (only if it changes).
998
- await self.tx(async (tx) => {
999
- (await tx.draft(drafts, conversation)).text = text;
1000
- }, ctx);
1001
-
1002
- // Branch on existence (keyed documents): read first, outside the transaction.
1003
- if ((await drafts.get(conversation, ctx)) === undefined) { … }
1004
- ```
1005
- - Document roots are `JsonObject` (as in Durable; lists live in a field); documents hold JSON only (bytes are a value
1006
- and wire type). A singleton that does not exist yet reads `initial()` through its handle; retiring resets it to
1007
- `initial()`. Handles may be used only in transactions of their own object.
1008
- - **Commit sequence** (Durable's): wait for the object's line (per object, never across objects; reads outside a
1009
- transaction do not take it exclusively); run the callback; an error or an abort before the storage write discards
1010
- everything; prepare every draft (Delta copies and checks only the placed values); write persisted documents in one
1011
- storage batch through the store's commit step, `await store.commit(writes, adopt, ctx)` without the caller's abort
1012
- signal (deltas, or a base when `checkpointWhen` says so; the line held until the step returned, as Durable's
1013
- `#runCommit`, owner, 2026-10-26); adopt by pointer swap and mark dependents in the step, persisted and in-memory
1014
- documents and staged changes in one `host.batch.commit` (errors as Durable's Storage, owner, 2026-10-27: a step that
1015
- fails before `COMMIT` rolls back and rejects that commit only, nothing adopted, the store goes on; plugin mistakes are
1016
- refused when a write is staged; a seal-fenced commit is rejected `released` before `BEGIN`); then the owner's synchronous flush recomputes dirty derives, sends one message
1017
- per link and queues watch callbacks (W1); drafts then throw if touched. In-memory-only commits take no store seq and never
1018
- enter the commit queue (W12). No
1019
- revalidation of the whole document, no copy, no freeze.
1020
- - **Nothing leaves a transaction before it commits (S2):** ids and data reach other owners only after the commit;
1021
- reference what is committed (a reference to a later commit dangles on every replica that stops in between).
1022
- - **Durable's rule:** inside the callback only `await tx.*`: no other objects, models, processes or network, no second
1023
- `self.tx`, no reads past `tx` (otherwise a hang, not an error). Fetch first; decide and write inside.
1024
- - A transaction covers only its own object's documents and tables: one line, no transactions across owners (facet
1025
- documents were removed, owner, 2026-10-26; shared plugin state is a `local` store object's, reached by methods).
1026
- - **Shorthands:** `handle.change(fn, ctx)` (keyed: `handle.change(key, fn, ctx)`) (one document, loaded before the synchronous `fn`),
1027
- `handle.retire(ctx)` (keyed: `handle.retire(key, ctx)`); several steps atomically: `self.tx`.
1028
-
1029
- ### Versions
1030
-
1031
- - A shape or meaning change raises `version` with a pure `migrate(old, from)`. A document migrates on access by the
1032
- new definition (in memory too); the migrated base is persisted with the next commit.
1033
- - **Schema fingerprints instead of value validation:** `defineState` computes the fingerprint of its structural schema
1034
- once (descriptions and titles ignored) and keeps it on the token; every document record stores the fingerprint it was
1035
- written with (at creation, and with the new base after a `migrate`). On access Chord compares the token's fingerprint
1036
- with the record's: the same version with a different fingerprint fails the object `broken` ("schema changed without
1037
- a version bump"). Always on, O(1). Every structural schema change needs a version bump (an additive change gets a
1038
- trivial `migrate`). Values are not walked against the schema in production, with two exceptions (R8):
1039
- - the result of `migrate` is validated against the new schema once, when it is produced (per document per version
1040
- change, off the commit path); a failure refuses the access, keeps the old data and fails the object (slice 6);
1041
- - `initial()` is checked once per definition, at its first value (D3, owner, 2026-10-24: `initial()` takes no input,
1042
- so a wrong shape is wrong at its first call; checking every call would cost one validation per created document
1043
- and catch nothing more). A failing singleton `initial()` fails its object's activation (`broken`); a failing
1044
- keyed one fails only the transaction that drafts the absent document, naming the definition (slice 1).
1045
- - Old code whose definition is older than the document throws on access. Without `migrate` the access is refused and
1046
- the data kept. A changed meaning without a bump cannot be detected.
1047
- - Singleton documents migrate during activation and after reload (hydration counts as access). A hydration or
1048
- migration failure keeps stored data and fails the whole owning object, not only the exposed member. Keyed
1049
- documents migrate on their next access; a migration failure there also fails their owner. A migrated base is written
1050
- back by the next commit that changes the document (owner, 2026-10-27); until then a load migrates again (once per
1051
- object, since documents stay on the object).
1052
-
1053
- ### Lifetime, persistence
1054
-
1055
- - **No tags (owner, 2026-10-21):** deleting a session deletes its store and directory; instance data on the server that
1056
- refers to a session is a table with a `session` column, cleaned up by its owner (`deleteWhere`, reconciling from the
1057
- catalog).
1058
- - **In-memory documents are instance state (P2, owner, 2026-10-21):** attached to the live object, with no storage, no
1059
- address, no seq and never in the outbox; their commit is prepare and adopt (inside the store's commit step when the
1060
- transaction also writes persisted data).
1061
- - **Lifetime:** in-memory documents end with their object (last reference released, linger expired, a params change on
1062
- reload) and survive reloads and native restarts of a live object; long-lived objects creating many keyed in-memory documents retire
1063
- them themselves. Persisted documents stay until retired.
1064
- - **Persisted data only in `local` objects with empty params (P3, owner, 2026-10-21):** persisted documents and tables
1065
- live in `local` objects with empty params (one per host and type); their address is (object type, name, key), never a
1066
- host instance such as the session id (W7; no host kind either since slice 6b R2: a store belongs to one host),
1067
- so a params change never orphans data. Per-entity data is keyed documents or table rows there, with an app-chosen
1068
- key; objects with params keep only in-memory state and read persisted data by key. Renaming a persisted store's type or
1069
- definition, or changing how keys are formed, is an explicit one-off migration in the store.
1070
- Why not elsewhere: a `remote` object's identity contains the principal key (provenance, grant revision), so its
1071
- persisted documents would scatter across access paths and be orphaned after a reconnect; a shared storage key
1072
- (`storeKey`) would put two objects with two lines on one document, so it does not exist; params would orphan data
1073
- on a params change. Enforced at the type level (`self.state(…, persist)` and `self.table` only in factories of
1074
- `local` types with empty params) and as a declaration error at runtime ("persist needs a stable identity: put the
1075
- documents into a local shared store").
1076
- - **Durable plugin state:** whatever must survive a host teardown (crash, restart, a DO eviction) is a persisted
1077
- document; everything else is rebuilt on activation (in-memory documents, natives, derives, routines, presence,
1078
- references re-held by clients; job runs end `lost` unless their records persist).
1079
-
1080
- ### Rules across owners
1081
-
1082
- - **No plugin reads or writes another plugin's documents** (Chord or Durable). Data crosses plugins only through
1083
- state and methods. Data core enforces lives in a format core owns and is handed to core through its API when the data is
1084
- created (`createConversation` with `init`), never written into core's documents directly.
1085
- - **Invariants across owners** are enforced by the owner of the dependent data, which reconciles from the other
1086
- owner's state with an idempotent routine. No cross-owner transactions, no "notify the other owner" calls that can
1087
- be lost:
1088
-
1089
- ```ts
1090
- // ports' ForwardStore: "a forward of an archived session is closed"
1091
- const catalog = self.get(Catalog, {});
1092
- self.on(catalog.sessions, async ({ value: sessions }, ctx) => {
1093
- for (const f of forwards.value.list) if (sessions[f.session]?.archived) await close(f.id, ctx); // idempotent
1094
- });
1095
- ```
1096
-
1097
- After a crash the routine runs again with the current value; sessions does not know ports exists.
1098
-
1099
- ---
1100
-
1101
- ## 10. Store and storage
1102
-
1103
- > **Superseded (owner, 2026-10-21):** persisted data lives in one transactional store per session, designed in
1104
- > `packages/chord/docs/next/store/book.md` and decided in the log ("The store", S1-S17, W1-W14, P2-P4, "Flat columns",
1105
- > "Query runner", "Index definitions are recorded", "Blobs and derived data"). In short: backends SQLite (Node, Durable
1106
- > Objects, sqlite-wasm in the browser; tests on SQLite `:memory:`, no hand-written memory backend, owner, 2026-10-27); real tables owned by objects with empty params (P3), flat
1107
- > columns (scalars, every `str()` as plain UTF-8 `TEXT` in code point order with lone surrogates replaced and NUL refused (owner, 2026-10-26, superseding W8), `json(...)` with its own version and on-access migration), a small
1108
- > query language, writes `put`/`update`/`delete`/`updateWhere`/`deleteWhere`; one documents engine for Durable
1109
- > (`StoreStorage`) and Chord; one commit queue per store that writes, adopts and marks (S1, W1), with `Storage.commit(
1110
- > writes, adopt, context)` in Durable; an outbox of ordered operations in the same transaction (no compaction at first);
1111
- > eager migrations by scan with row `v` for eager steps only. In-memory documents are instance state with no storage
1112
- > (P2). The text below describes the per-object lines, Delta trackers and commit sequence, which stay; its storage
1113
- > interface is replaced by the store.
1114
-
1115
- - **What stays from Durable's store design** (`durable/src/session/transaction.ts`, `session.ts`): one Delta tracker
1116
- per document held by its object, prepare and adopt by pointer swap, ops per commit, lines per object, migrate on
1117
- access, `checkpointWhen` (required for persisted documents, R14), retire, and the documents engine's invariants (create before change, no
1118
- change after retire, one live incarnation per address, `deltasSinceBase`).
1119
- - **Where persisted documents live:** rows of the store's documents engine (S13) with address `(namespace: "chord",
1120
- owner: "<object type>", kind: <definition>, key)` (key `""` for a singleton), never a host instance (W7); ids from the store's
1121
- counter (S10). Chord ships no storage of its own: no `DocumentStorage` interface, no Chord SQLite or memory document
1122
- storage and no Chord storage conformance suite (the store's conformance suite covers the engine); the frozen `next/`
1123
- storages are not ported. The store is passed to the session's host by base code (owner, 2026-10-26):
1124
-
1125
- ```ts
1126
- const store = await openStore(sqliteBackend(await openNodeSqliteDatabase(join(dir, "session.sqlite"))), ctx);
1127
- const worker = createHost<P>({ address: Session({ id }), principal, store, onError }); // tests: SQLite :memory:
1128
- …
1129
- await worker.close(ctx);
1130
- await store.close(ctx); // the app owns the store; in 6b the Durable Session shares it
1131
- ```
1132
-
1133
- `openStore` runs the store's own migrations, checks the file is UTF-8 and reads `lastSeq`, the definitions and the
1134
- id counters once; `sqliteBackend(db)` takes any `SqliteDatabase` (Node, Durable Objects, sqlite-wasm later); the
1135
- backend interface is internal; `importStore(backend, archive, ctx)` takes the same backends. No `openNodeStore`.
1136
- - **Loading at activation (owner, 2026-10-26):** persisted singletons load right after the factory, sequentially,
1137
- all singletons of the object with plain reads (owner, 2026-10-27: the object holds its line, so no read transaction
1138
- is needed), once per object, before its references are bound: find, load (base plus
1139
- deltas), fingerprint check, `migrate` with its result validated once (R8). A storage error is `storage_failed`; a
1140
- fingerprint mismatch, a throwing `migrate` or an invalid migration result fails the object `broken`.
1141
- - **Statements per commit (owner, 2026-10-26):** the store keeps `lastSeq` (the seq of its last commit) in memory (read at open,
1142
- persisted with each commit, S9) and folds the documents engine's checks into the writes (unique keys, a partial
1143
- unique index on the live address, conditional `UPDATE … WHERE id = ? AND version = ?`): a delta commit is about three
1144
- statements (revision, the record's counted conditional `UPDATE`, `lastSeq`), plus one `INSERT` with an outbox. Durable's ids in the store (slice 6b D3): one id allocator per store
1145
- for every id (Durable's `mintId` and Chord's document ids; it starts at 2, saturates at `Number.MAX_SAFE_INTEGER`, each
1146
- commit persists it, outbox commits and archives carry it as `nextId`); `StoreStorage`'s `record_ids` table only checks
1147
- an id's record type. Every table and document namespace in the store is claimed once (slice 6b "owner names and
1148
- claims"): a table by its SQL name `"<owner>:<table>"`, documents by `(owner, namespace)`; an object claims under its
1149
- type, `StoreStorage.open(store, owner, ctx)` under `owner` (two harnesses on one store under two names are fine).
1150
- - **Tables in a transaction (owner, 2026-10-26):** the table handle first, keys as objects with exactly the key
1151
- columns, reads async, writes synchronous and buffered like a draft's ops (checked and staged, no I/O; written in the
1152
- commit step or dropped on failure); no write shorthands on the handle:
1153
-
1154
- ```ts
1155
- self.tx(async (tx) => {
1156
- const old = await tx.get(edits, { id }); // overlays own put/update/delete (W10 after bulk)
1157
- const { items, next } = await tx.page(edits, q, 50, { after }); // committed rows, stable for the transaction
1158
- tx.put(edits, row);
1159
- tx.update(edits, { id }, { at: now });
1160
- tx.delete(edits, { id });
1161
- tx.updateWhere(edits, (e) => prefix(e.path, from), (e) => ({ path: replacePrefix(e.path, from, to) }));
1162
- tx.deleteWhere(edits, (e) => lt(e.at, cutoff));
1163
- }, ctx);
1164
- await edits.get({ id }, ctx); // outside: committed state, ctx last
1165
- ```
1166
- - **The outbox (owner, 2026-10-26):** optional, `openStore(backend, ctx, { outbox: true })` (an omitted option keeps the
1167
- persisted setting; switching needs an explicit `true` or `false`), persisted in the store's
1168
- metadata (turning it on starts sync from an archive at the current `lastSeq`); a table in the store's backend,
1169
- written in the commit step's transaction (atomic for one `INSERT`); exposed as `store.outbox.read(afterSeq, limit,
1170
- ctx)` -> `{ seq, writes }[]` and `store.outbox.trim(throughSeq, ctx)`, no pluggable encoding; versioned by the store's
1171
- schema migrations (its layout) and a `format` per outbox commit (the write vocabulary, the archive's `format`; older
1172
- formats stepped forward on read, newer ones refused).
1173
- - **Writes, commits, batches, archives (owner, 2026-10-26):** a *write* (`StoreWrite`, tagged by `kind`) is one change
1174
- of the store (`put`, `update`, `updateWhere`, `table`, `index`, `document.create`, …); a *commit* the writes of one
1175
- seq in the outbox; a *batch* the commits `from..to` that sync uploads and a replica applies; an *archive* a manifest,
1176
- the writes from 0 to `lastSeq` and an `end`. `lastSeq` is the seq of the store's last commit.
1177
- - **Export and import (owner, 2026-10-26):** `store.export(ctx)` yields the archive's parts, the state after its
1178
- `lastSeq` as writes (manifest, `table`, `index`, `put`, `document.create`, `end`), holding the commit queue
1179
- until the iteration ends or `ctx` aborts; `importStore(backend, parts, ctx)` applies them into an empty backend in
1180
- one transaction with the replica's applier. Lossless (owner, 2026-10-26): every `put` write carries its versions (`$v`,
1181
- each `json(...)` column's) in the outbox and in archives, a `table` write its state, a `latest` document its current
1182
- value; the applier never infers a version. The encoding is pluggable; plain JSONL ships first. Sync is not export:
1183
- it ships outbox batches as commits happen.
1184
- - **`json(schema, { version, migrate? })` columns (owner, 2026-10-26):** schema and version required, `migrate`
1185
- optional and pure, on access (W11), its result checked once (R8); without it (or failing) the read is refused and
1186
- the owner fails `broken`; each column's version and schema fingerprint are recorded in the table definition and
1187
- compared at activation (same version, other fingerprint: `broken`, D9); a read never writes back.
1188
- - **Table versions: `evolveTable` (2026-10-27, the second spec review's majority):** a table's history is a base
1189
- (`defineTable`) and one `evolveTable(prev, (t) => t.rename(…).add(…).rows(…).drop(…).index(…))` per version, each
1190
- materialized and fingerprinted at declaration, as contracts' `evolve`; the store replays the recorded version's
1191
- successors in order (DDL and `migrating`, the data step, `ready`); key columns are immutable in `set`.
1192
- - **Eager migrations and addresses (owner, 2026-10-26):** the activation attempt's `readyTimeout` deadline does not
1193
- run while an eager migration step runs (getters still time out by their own). Store names carry no host kind (slice
1194
- 6b R2, owner, 2026-10-27): tables are `"<object type>:<table>"`, document owners `"<object type>"`.
1195
- - **Eager `rows` migrations** commit in chunks of 100 rows (owner, 2026-10-26; a fixed constant: about 1 ms of commit
1196
- step per chunk, the total time is the same for larger chunks, and every other owner's commit waits for the step).
1197
- Between chunks the migration yields one macrotask without `setTimeout`'s 1 ms clamp: `setImmediate` where the
1198
- runtime has it, otherwise a `MessageChannel` message (2026-10-27, slice 6a build reviews).
1199
- - **Eviction as in Durable,** for keyed persisted documents only (persisted singletons and `at(key)` documents stay
1200
- in memory while their object lives: `handle.value` is a synchronous read; owner, 2026-10-26): one not read, written or watched for the retention
1201
- period (default 10 minutes) leaves memory and reloads on the next access. **Store errors (owner, 2026-10-27; supersedes in part "Store errors: Durable's rule"):** the store has Durable's
1202
- `Storage` semantics, its owners react as Durable's Session does. A step that fails before `COMMIT` rolls back: that
1203
- commit rejects, nothing is adopted, the store goes on. The store stops (`storage_failed`: later calls reject
1204
- `unavailable/storage_failed`, the host closes, `onError` receives `{ kind: "storage_failed" }`, the app decides,
1205
- section 3) only when the outcome is unknown (`COMMIT` or `ROLLBACK` failed) or `adopt` threw, and on a backend
1206
- error of a read whose `ctx` was not aborted. A Chord object whose commit the step refused (memory and disk disagree:
1207
- the counted conditional `UPDATE`, the live-address index) fails live (`object_failed`, `broken`); an `int` result out
1208
- of range (`CHECK`) fails only that transaction (`invalid/args`). Durable's Session fails on any commit error
1209
- (`GuardedStorage`), as today.
1210
-
1211
- ---
1212
-
1213
- ## 11. Kinds of state
1214
-
1215
- | Kind | For | API |
1216
- | --- | --- | --- |
1217
- | document | data the object owns | `self.state`, `self.tx` |
1218
- | derive | computed values | `self.derive(sources, fn)` |
1219
- | Durable's views | the conversation view, task graph and Durable documents | `Watchable`s through Durable's watches; feed derives and state members |
1220
- | paged method | large or queryable collections | a method returning pages (chat history) |
1221
- | table | a plugin's own records with queries (owner, 2026-10-21) | `self.table`, the store's query DSL |
1222
- | plugin database | derived data only: full-text search, caches (rebuilt, never synced) | a native opened by its owner |
1223
-
1224
- App state lives in Chord documents; only transcript-bound data (entries, documents that fork and rewind with a
1225
- conversation) lives in Durable.
1226
-
1227
- ### Watchables (owner, 2026-10-21; log "Watchable and one watch API", W1-W4)
1228
-
1229
- There is no `replicatedState` in v2. Everything observable is one of two kinds, sharing one lifecycle:
1230
-
1231
- ```ts
1232
- interface Watchable<T extends JsonValue> { // JSON only (no bytes); documents, derives, reference members, constant(v), Durable's views
1233
- readonly value: T;
1234
- watch(ctx: Context): Promise<WatchHandle<T>>; // listener (call, ctx), call: WatchCall<T> (below)
1235
- }
1236
- interface NativeWatchable<T> { // self.writable(initial) with set(), composed registry values
1237
- readonly value: T;
1238
- watch(ctx: Context): Promise<NativeWatchHandle<T>>; // listener (call, ctx), call: NativeWatchCall<T>; a change is a new value (!==)
1239
- }
1240
- type WatchCall<T> = // owner, 2026-10-27: a recoverable failure is a call, the watch stays open
1241
- | { kind: "value"; value: T; ops: Op[]; retired: boolean }
1242
- | { kind: "failed"; error: unknown };
1243
- type NativeWatchCall<T> = { kind: "value"; value: T } | { kind: "failed"; error: unknown };
1244
- // const w = await notes.watch(ctx); send(w.value);
1245
- // w.start(async (call, ctx) => { if (call.kind === "failed") return showError(call.error); render(call.value); });
1246
- // … await w.stop();
1247
- ```
1248
-
1249
- - **Failures are calls, watches end only for good (owner, 2026-10-27):** a source that fails and can recover (a
1250
- derive whose compute throws, a replica member a hold lists as failed, a member a new variant lacks, a registry whose
1251
- `compose` throws, slice 8) gives its watches one `{ kind: "failed", error }` call and keeps them open; its next good
1252
- value arrives as `[["r", value]]` (folded with the failure for a busy listener). A failed derive recomputes on every
1253
- later change of its sources and on a re-bind (self-healing). A watch ends only when nothing can come back: its owner
1254
- ended (`ended`), `stop()` or a cancelled context, a throwing listener (`listener_error`), `storage_failed`. `self.on`
1255
- handlers are not called for failures: a routine waits for the next good value (the failure is reported where it
1256
- happens: the derive's owner reports `derive_failed { object, member?, error }` once per failure episode, the first
1257
- failure after a value or after creation, not for a derive failing only because a source failed). `ref.state` stays
1258
- a separate watchable of the object's reachability (`loading | live | failed | ended`), with the same words. A
1259
- replica member that vanished with a variant is kept and comes back with a later binding; while failed it accepts
1260
- only `[["r", value]]`.
1261
- - **Watch handles are Durable's, moved into Chord** (Durable imports them): `watch()` atomically takes the current
1262
- value and buffers later commits; `start(listener)` installs the one listener; commits are delivered in order, async
1263
- listeners awaited; a listener still busy with an earlier frame gets the commits made meanwhile as one call, from
1264
- the **pending queue** (owner, 2026-10-23): ops stay raw and are folded through a leaf index (a map from path to
1265
- the last pending append or primitive set; a new one on that path merges into it; any structural op clears the
1266
- map; `r` drops everything before it); past 10,000 pending ops only "replace with the current value" is kept (no
1267
- size, text or time caps; no folding of list appends or trims; ops come only from Chord's tracker and
1268
- `diffRevisions`, so there are no defences against hand-written ops). `PendingOps` is Chord's shared Delta code. The
1269
- same queue holds a link hold's ops while its window is full (section 3). Natives: every value in order, past 100 pending values one call with the newest (W4). Durable's
1270
- event stream keeps its own queue (events are not state); `stop()` is idempotent, drops pending frames, never aborts or awaits a running call; `stop()` and
1271
- `closed` return the end, tagged by `kind` (owner, 2026-10-27): `stopped`, `aborted` (its context aborted), `ended`,
1272
- `listener_error { error }`, `failed { error }` (a final failure; a recoverable one is a call). Durable's synchronous
1273
- observers take the same shapes: `advance(call, ctx)`, `end(end)`.
1274
- **Retirement (owner, 2026-10-26, option A; replaces W2a's `[["r", null]]` frame and the end `retired`):** one
1275
- mechanism for Chord and Durable documents, singletons and keyed alike. A watch follows its document's address; a
1276
- retirement is one last call with a `retired` flag (a Chord document: `initial()` with `[["r", initial()]]`, which a
1277
- wire replica applies; a Durable document: the last good value, no ops); the watch goes on, and a later
1278
- write delivers the new incarnation as `[["r", value]]`. A watch ends `ended` with its owner (the object of a Chord
1279
- document; for Durable the task of a task document, right after its retirement call, or the Session). Listeners take
1280
- one object before the context (owner, 2026-10-26; tagged since 2026-10-27, above): `(call, ctx)`, a `WatchCall` or
1281
- `NativeWatchCall`.
1282
- A retirement call carries the address's value after the retirement: `initial()` for a Chord document, the last value
1283
- (no ops) for a Durable one, which has none while absent. Watching an absent address gives `undefined`. On the wire a
1284
- `state` entry lists retired members like failed ones. A per-key source in a factory, `handle.at(key)`, is a singleton per key: loaded at activation, `initial()` while absent, usable as a state member, derive source and `on` source (owner, 2026-10-26). A
1285
- stopped watch releases every reference it held (W3).
1286
- - **Only `Watchable<Json>` can be a contract state member or go on the wire**, by type and by a kind check when the
1287
- object is served (Q14); a `NativeWatchable` never can, even holding JSON. Mutating a native value in place notifies
1288
- nobody.
1289
- - **Publication (W1):** the commit step writes, adopts (pointer swaps, Durable's touched views dispatched by id) and
1290
- marks (dirty derives; ops appended by reference to each touched hold's batch and each watch's queue). Right after
1291
- the step, synchronously, the owner's flush recomputes the dirty derives someone holds or watches (dependency order),
1292
- encodes one entry per touched hold into one `state` message per link and origin, and queues watch callbacks. A
1293
- throwing derive fails only its member; reentrant `self.tx`/`watch`/`release`/`get`/`hold`/`load`/`close` throw
1294
- `invalid/reentrant`; a delivery or flush that throws is reported (`delivery_failed`) and the others still run. The
1295
- same boundary runs without a store seq for in-memory commits, `writable.set`, registry changes and inbound wire
1296
- batches (a `bound` or `state` message is applied as one batch before listeners run). There is **one batch per host**,
1297
- passed to its sources (no module-level singleton); a dirty derive nobody holds or watches recomputes lazily on its
1298
- next read.
1299
- - **Consumers:** derives and the wire use the internal flush; app code uses watches; `self.on` is a watch owned by
1300
- the object (first call with the current value, then every commit; Chord awaits a running call on reload); clients
1301
- get ordered ops over the link, folded by the provider's pending queue when they fall behind (section 3); a re-hold
1302
- gets a fresh snapshot.
1303
-
1304
- ---
1305
-
1306
- ## 12. Derives
1307
-
1308
- `self.derive(sources, (values) => value)`: a synchronous pure function, recomputed when a source changes and
1309
- diffed into ops for the wire. Sources are `Watchable`s and `NativeWatchable`s (documents, other derives, reference
1310
- members, Durable's views, registry values); the result is always JSON (state is JSON only; bytes only in method arguments and results). A derive is marked dirty in the
1311
- commit step and recomputed in the owner's flush right after it, so its change travels in the same message as its
1312
- source (W1); a dirty derive nobody holds recomputes on its next read. A throwing derive fails only its member
1313
- (`broken`). There is no `previous` (W14): `mapShared` keeps unchanged elements identical.
1314
-
1315
- - **Built on what exists:** derives sit on Chord's internal publication primitive (not today's `cell.ts` or
1316
- `replicatedState`); the diff is
1317
- Delta's `diffRevisions` called directly (identity short-circuit: unchanged shared subtrees cost one `===`; bytes are
1318
- atomic leaves compared by identity; equality never by stringify).
1319
- - **Container width (R24):** structural sharing is O(change) along a path, not across a container's width: changing
1320
- one item of a flat array copies the array's slots, and `mapShared` visits every element (one identity comparison
1321
- each). Large collections are keyed documents or bounded windows; a benchmark of long arrays (allocations, element
1322
- visits per change) sets the documented limit.
1323
- - **The footgun:** a derive that builds new objects for unchanged data makes every commit cost O(size of the value),
1324
- per view, because the diff must compare contents. Unchanged parts must be the same objects as last time.
1325
- - **`mapShared(f)`** (from `@earendil-works/chord/next` state; it moves into Delta when v2 goes upstream): an identity cache per source element: `f` runs only for new or
1326
- changed source elements, unchanged ones return their previous result object. With it a list derive costs pointer
1327
- comparisons, not content comparisons:
1328
-
1329
- ```ts
1330
- const strip = mapShared((n: Note) => ({ text: n.text, at: n.at })); // a mapper over the whole array
1331
- self.derive([notes], ([n]) => ({ list: strip(n.list) }));
1332
- // one appended note: one new object, 2,000 identical references, diffRevisions emits one insert
1333
- ```
1334
-
1335
- - **Cookbook** (documentation with examples per case): select a field, look up by key, small aggregates (just compute;
1336
- the value is small); filter or map a list (`mapShared`); redaction (preferably separate documents per visibility,
1337
- otherwise `mapShared`; computed once in the shared store, not per view); joins across two sources (`mapShared` plus
1338
- the looked-up source's revision); a window over a large list (take a section of the source elements without
1339
- rebuilding them, cache per-element measurements by identity, keep the window's start stable so changes arrive as
1340
- appends). Large combined views from several sources re-path the sources' ops (as Durable's `ConversationView`);
1341
- application code never interprets ops.
1342
-
1343
- ---
1344
-
1345
- ## 13. Natives
1346
-
1347
- ```ts
1348
- const watcher = self.open(async (context) => watchDir(path, { signal: context.abortSignal }), (w) => w.close());
1349
- self.onLive(async (ctx) => { for await (const f of watcher.value.files(ctx.abortSignal)) await importFile(f, ctx); });
1350
- ```
1351
-
1352
- - `self.open(open, close, { closeTimeout? })` (slice 2): `open(context)` gets a context aborted when the attempt is
1353
- abandoned (a timeout, a cycle, its end); `close(value, reason, context)` gets one aborted at the close timeout, after
1354
- which a possible leak is reported (`close_timeout`) and the rest continues. It returns a handle with `.value`, not a
1355
- proxy: reading it before its open resolved throws `not_ready`, after its close started `released`. A value that
1356
- arrives after its attempt was abandoned is closed at once.
1357
- Natives open during activation (the object goes live after all opens) and close in reverse order when it ends.
1358
- The opened value never changes during that attempt: no `self.resource`, versions, `replace`, `deps` or stale
1359
- handles. To change a live native, the object restarts. A partly failed activation closes already-open natives
1360
- with reason `end`; a later attempt opens them all anew. `retryOn` may appear anywhere in the synchronous factory.
1361
- Type names: `Native<T>` (the handle), `NativeCloseReason`.
1362
- - **Order:** natives open one after another in declaration order (a later opener may use an earlier handle's
1363
- `.value`) and close in reverse. A throwing `close` does not stop the others: on `host.close()` all errors are
1364
- collected and it rejects with them; an object ending in the background reports them to `onError`.
1365
- - Behaviour around a native goes into routines; listeners on natives outside routines are forbidden.
1366
- - The facet may not open natives.
1367
- - What an old native does after its owner restarts is its owner's `close` (a model runtime keeps working until
1368
- collected; a closed SSH connection fails its in-flight `exec`).
1369
- - An open that fails makes the object `failed` (`transient` with backoff, or `broken` if it says so).
1370
-
1371
- - **`close` gets a reason:** `reason: { kind: "reload" } | { kind: "close" } |
1372
- { kind: "end" }` (the plugin is reloaded and the object is native / the host shuts down / the last reference ended or
1373
- the type was removed). Chord aborts only the object's own calls and jobs; other work using the native (Durable tool
1374
- executions on a code mode sandbox) is the owner's: `close` may drain instead of tearing down, e.g. seal the sandbox
1375
- (no new scripts) and end it when its running scripts finish or hit their deadline.
1376
- - **Restart stays sequential (R16):** close the old native, then open the new one. Two patterns for natives whose
1377
- resource has work in flight:
1378
- - **Drain in the background:** `close` detaches the old resource, returns at once, and disposes of it when its work
1379
- has finished or after `closeTimeout` (30 s at most, Q7: a longer script is aborted); Chord then opens the new one
1380
- immediately. Code mode's sandbox does
1381
- this; its tool entry looks up the current sandbox at `execute()`.
1382
- - **Swap through a registry:** the resource is a registry contribution; readers always find the current one, and a
1383
- reader that must wait for one uses a cancellable "wait until present" with the park deadline.
1384
-
1385
- ---
1386
-
1387
- ## 14. Routines
1388
-
1389
- Two kinds, declared in the factory (owner, 2026-10-24; C4 decided; slice 5):
1390
-
1391
- ```ts
1392
- self.on(catalog.sessions, async ({ value: sessions }, ctx) => { // reacts to a value: first the current one, then every change
1393
- for (const f of forwards.value.list) if (sessions[f.session]?.archived) await close(f.id, ctx); // idempotent
1394
- });
1395
- self.onLive(async (ctx) => { // called once when the object goes live
1396
- for await (const file of watcher.value.files(ctx.abortSignal)) await importFile(file, ctx);
1397
- });
1398
- self.onLive(async (ctx) => { // periodic: a loop with sleep
1399
- for (;;) { await sleep(HOUR, ctx); await dropOld(ctx); }
1400
- });
1401
- self.onLive(async (ctx) => { // set up, wait for the end, clean up
1402
- const timer = setInterval(tick, 1000);
1403
- try { await untilAborted(ctx); } finally { clearInterval(timer); }
1404
- });
1405
- ```
1406
-
1407
- - **Lifecycle (both kinds):** declared in objects, never in facets (owner, 2026-10-26: everything is done through
1408
- objects); they start when the object goes live (in the same turn)
1409
- and stop when it ends (their `ctx` is aborted, then
1410
- the drain waits for running calls, bounded by `closeTimeout`). Each call gets its own `ctx` (the object's principal
1411
- for a remote type, the host's for a local one; the host's incarnation; `ctx.get` released when the call settles).
1412
- - **On reload** the old routines' `ctx` is aborted; the new routines start once all old routine calls of the object
1413
- have finished (bounded; a stuck call is reported and the new routines start anyway): a handover per object, so
1414
- routines need no names. Example it prevents: an old handler midway through `restart(W1)` and a new one seeing W1
1415
- still pending and restarting it again. The bound is `closeTimeout` (owner, 2026-10-24); calls do not wait for the
1416
- handover, only the new routines do (slice 7b). A stuck old call past the handover is reported `drain_timeout` and
1417
- the whole old attempt is sealed then (audit A12: one seal token per attempt; its method calls had the same bound).
1418
- - **`on(source, fn)`:** any watchable (a document, a derive, a reference member, a registry value, `ref.state`). The
1419
- first call gets the current value (`[["r", value]]`, W2b), then one call per change; calls never overlap (S8);
1420
- changes made during a call arrive folded in the next (newest value, folded ops); a running call is not aborted by a
1421
- change (native sources too: a busy call is followed by one call with the newest value). A throwing call is
1422
- reported and called again with the current value after a backoff (1 s doubling to 60 s;
1423
- a change during the backoff calls at once; success resets it). The source ending (a released reference, its object's
1424
- end) ends the routine without a report; a retired document does not end it (the call has `retired: true`).
1425
- - **`onLive(fn)`:** called once when the object goes live. Returning ends it until the next reload or activation;
1426
- throwing is reported and restarts it after the same backoff (reset after a run of at least a minute); an abort is
1427
- no error.
1428
- - **Idempotent reconcilers:** a routine reconciles from the current value, writes no "in progress" flags and starts a
1429
- job for long work. Chord keeps no state for routines across reloads or restarts; what must survive is a document of
1430
- the object (e.g. a `lastCleanup` time, which also survives a crash).
1431
- - **Helpers:** `sleep(ms, ctx)` (rejects when `ctx` is aborted, leaves no timer or listener) and `untilAborted(ctx)`.
1432
- Routines and handlers wait only through calls that take `ctx`; otherwise Chord cannot stop them, and the handover
1433
- and the drain report them stuck.
1434
- - **Errors:** `onError` gets `routine_failed { object, routine, error }`, `routine` a `Position` (`{ kind: "on" |
1435
- "onLive", position }`; natives use the same type); never uncaught.
1436
- - **Keep-alive:** routines do not count in `host.activity` (an `onLive` runs forever).
1437
- - No bare timers or callbacks that touch state outside routines, jobs or calls. Gone (C4): `every` (an `onLive` with
1438
- `sleep`), `custom` and its `run(fn)` (an `onLive` with `try`/`finally`; callbacks that must run one at a time go
1439
- through a small queue or the source's async iterator), names, a due time kept across reloads.
1440
-
1441
- ---
1442
-
1443
- ## 15. Jobs
1444
-
1445
- Owned work a call starts that outlives the call (a shell command, a session clone, a peer send, a login's work), in
1446
- Durable's sandwich: **intent** (a transaction), **run** (any effect), **finish** (a transaction on the current code).
1447
- Decided with the owner on 2026-10-24 (decision log "Routines and jobs open points", "Jobs keep accepts", "Job crash
1448
- handling"; C3 settled this way); slice 5 builds jobs in memory, slice 6 persistence, slice 7 their reload rules.
1449
-
1450
- ```ts
1451
- const ShellState = defineState("chat.shell.state", {
1452
- schema: obj({ output: str() }), version: 1, initial: () => ({ output: "" }),
1453
- });
1454
- const ShellJob = defineJob("chat.shell", {
1455
- version: 1,
1456
- args: obj({ command: str(), author: Author }),
1457
- result: obj({ exit: int(), output: str() }),
1458
- state: ShellState, // optional: one document per run
1459
- concurrency: 1, // optional: at most one active run per object
1460
- });
1461
-
1462
- host.serve(ChatStore, ({ conversation }, self) => { // local: no principals; views filter (below)
1463
- const entries = self.state(ChatEntries);
1464
- const shell = self.job(ShellJob, {
1465
- run: async ({ command }, ctx) => {
1466
- const out = new OutputBuffer({ maxLines: 2000, retain: "tail" });
1467
- const progress = throttle(100, () => ctx.state.change((d) => { d.output = out.snapshot().text; }, ctx));
1468
- try {
1469
- const r = await runProcess(command, ctx.abortSignal, (chunk) => { out.push(chunk); progress.schedule(); });
1470
- return { exit: r.code, output: out.snapshot().text };
1471
- } finally {
1472
- await progress.flush(); // the last output reaches outcome.state, also after an abort
1473
- }
1474
- },
1475
- finish: async (outcome, tx) => {
1476
- const list = (await tx.draft(entries)).list;
1477
- list.push(outcome.kind === "done"
1478
- ? shellEntry(outcome.args, outcome.result)
1479
- : shellEntry(outcome.args, { interrupted: outcome.error.kind, output: outcome.state.output }));
1480
- }, // the run's state document is retired in this commit
1481
- });
1482
- return {
1483
- shells: shell.running,
1484
- runShell: async ({ command, author, requestId }, ctx) =>
1485
- ({ id: (await shell.start({ command, author }, ctx, { key: requestId })).id }),
1486
- abortShell: async ({ id }) => shell.abort(id),
1487
- };
1488
- });
1489
- ```
1490
-
1491
- - **Definition:** `defineJob(name, { version, args, result, state?, concurrency?, accepts?, persist? })`. `args` and
1492
- `result` are schemas; `state` is a document definition (a singleton, one document per run); `persist` arrives with
1493
- slice 6. `self.job(Job, { run, finish? })` is declared in an object's factory (not in a facet) and returns the job
1494
- handle: `start(args, ctx, { key? })` (a `Run { id, outcome(ctx) }` after the commit), `tx.start(job, args, { key? })`
1495
- inside `self.tx` (a `Run` handle at once, whose `outcome` rejects if the transaction is discarded), `outcome(id, ctx)`
1496
- (unsettled runs only), `abort(id, ctx)` (`"marked" | "terminal"`, as Durable's `abortTask`: stored, resolves once `run` settled; slice 6b) and `running`.
1497
- - **1. Intent:** one transaction on the owner's line. Arguments are checked against `args` (closed schema, like
1498
- method arguments). Dedupe first: a run with the same `key` that is not settled is returned as it is (the run whose
1499
- `finish` this transaction is never counts, so `finish` can start the same job again with the same key). Then the
1500
- `concurrency` check: at the limit `start` rejects with `unavailable/busy` (a queue is the owner's, built from a
1501
- document and a routine). Otherwise a run record `{ id: uuidv7, version, args, key }` and its state document
1502
- (`initial()`) are written in the commit, with whatever else the transaction writes (`tx.start`: a request entry and
1503
- the run, both or neither). `run` starts after the commit.
1504
- - **2. Run:** `run(args, ctx)` may do anything, outside transactions. `ctx` is a `Ctx` (the object's principal for a
1505
- remote type, the host's for a local one) plus `jobId` and `state`: `ctx.state.value` (synchronous) and
1506
- `ctx.state.change(fn, ctx)` (a transaction on the owner's line on the run's document, without the run's abort signal).
1507
- State changes are accepted until `run` settles, also after an abort (so output written while stopping still reaches `outcome.state`), and are
1508
- refused (`released`) afterwards, never recreating a retired document. Each change is a commit and, while someone
1509
- watches, a message: authors throttle frequent changes themselves (Chord does not coalesce them); awaiting or
1510
- catching each change is the author's (an unhandled rejection is the author's bug). External writes carry keys made
1511
- from `ctx.jobId`. A `run` that throws after its signal fired ends `aborted`, otherwise `threw` (reported as
1512
- `job_failed`).
1513
- - **3. Finish:** when `run` settles, Chord records the outcome on the run (`phase: "finishing"`), then calls the
1514
- current code's `finish(outcome, tx)` in a transaction (Durable's rule: only `await tx.*`). In the same commit Chord
1515
- deletes the run record and its key (Q9: dedupe covers unsettled runs only) and retires the run's state document. A
1516
- `finish` that throws changes nothing: it is retried with backoff (1 s doubling to 60 s), each failure reported
1517
- (`job_finish_failed`); after five consecutive failures the run is `blocked { finish_failed }`, its outcome, state
1518
- and key kept, retried on the next reload. `finish` is optional (then the commit only cleans up).
1519
-
1520
- ```ts
1521
- type Outcome<Args, Result, State> = { readonly id: string; readonly args: Args; readonly state: State } & (
1522
- | { readonly kind: "done"; readonly result: Result }
1523
- | { readonly kind: "failed"; readonly error: JobError }
1524
- );
1525
- type JobError =
1526
- | { readonly kind: "threw"; readonly error: ChordError | PluginError } // run threw (reported)
1527
- | { readonly kind: "aborted"; readonly reason: "abort" | "reload" | "restart" }
1528
- | { readonly kind: "restart_limit"; readonly restarts: number }; // persisted runs (slice 6b)
1529
- // abort(id); a native restart on reload, in-memory runs (slice 7b); "restart": a persisted run abandoned after a crash (slice 6b),
1530
- // or a run cut off by its attempt's seal while the object continues (slice 6a)
1531
- ```
1532
- - **Abort is a request:** `abort(id)` fires `run`'s `ctx.abortSignal`; `run` decides what it returns (a result that
1533
- already arrived stays a success); a run ignoring the signal keeps its slot. Abort of a finishing run does nothing;
1534
- abort of a blocked run drops it (no `finish`, its record, key and state document go, reported; owner, 2026-10-24).
1535
- - **Waiting:** `run.outcome(ctx)` resolves with the outcome once `finish` committed; the caller's abort ends only its
1536
- wait. Across a link nobody waits on a long call: UIs watch state.
1537
- - **`running`:** a JSON watchable, one entry per unsettled run, tagged by phase:
1538
- `{ id, version, key?, args, state, phase: "running" | "finishing" } | { id, version, phase: "blocked", reason }`. A
1539
- blocked run carries no `args` or `state` (it may be of another version than the code); views filter it as they
1540
- filter anything. Per-principal views derive what each principal may see (§6, the shared store): a reader without
1541
- output, a guest only their own runs.
1542
- - **Concurrency and keep-alive:** `concurrency` counts runs that are running or finishing; blocked runs do not count.
1543
- **Runs belong to the object** (owner, 2026-10-26): records, keys, the active count, `running`, run state documents
1544
- and pending actions are the object's, across attempts and native restarts; an attempt has the implementation and
1545
- its running invocations; a run's state changes and outcome are fenced by the run's own invocation; `finish` runs
1546
- on the current live attempt. **Jobs keep their object alive** (D4): running and finishing runs are a count on the object, not references (they
1547
- never appear in `host.references`); an object whose last reference goes stays while the count is above zero, and
1548
- ends (after its type's `linger`) when it reaches zero, dropping blocked runs with a report. `host.activity.jobs`
1549
- counts them.
1550
- - **Object end:** revocation (R11), `host.close` and a reload that removes the type end the object at once: runs get
1551
- the abort signal, the drain is bounded by `closeTimeout`; an in-memory run's outcome and state go with the object
1552
- (no `finish`). Jobs in `local` stores are never revoked (no principal): a store that runs work for a principal keeps
1553
- the grant as data and reconciles with a routine (§25).
1554
- - **Versions (`accepts`, slice 7b §8):** a job is versioned like everything else; `accepts` maps an older version's args
1555
- forwards and its result forwards (`{ 1: { args: (old) => current, result: (old) => current } }`; a producer's
1556
- direction, unlike a contract's). Its records keep every run's version: a new attempt's `self.job(Def, impl)` at
1557
- another version takes the records over (the same version with another fingerprint, over args, result and state, is
1558
- refused at declaration, as documents). A run started on an older version and still running finishes on its old
1559
- code across a pure swap (its invocation keeps the old implementation); `finish` runs on the new code with the
1560
- outcome's args and result mapped forwards (once per run, never per publication); `running` shows its args mapped; a
1561
- run not invoked yet runs on the new code with its args mapped. Its state document keeps its version while the old
1562
- code writes it and migrates through its own `migrate` once its run settled or moved to the new code (the outcome
1563
- `finish` gets). Without an adapter, for a run of a newer version than the code (a rollback), or for a job the new
1564
- code no longer declares, the run is `blocked { version }` (kept, not invoked) until a reload brings matching code;
1565
- blocked runs (`finish_failed` ones too) are retried on every reload of their object's plugin; a persisted run of
1566
- another version or fingerprint stays blocked with its record as stored until the reload that brings its version
1567
- resumes it. A native restart aborts running in-memory runs (`aborted { reason: "reload" }`) and `finish` runs on the
1568
- new code; persisted runs are stopped and resumed per their `resume` (6b R3, owner, 2026-10-29). A `finish` in flight
1569
- across a reload completes on the code it started with; the next one runs on the new code. A version change aborts
1570
- nothing and discards nothing.
1571
- - **Persistence (slice 6):** `persist: { resume: "rerun" | "abandon" }` keeps the run record and its state document
1572
- in the owner's store (owner: a `local` object with empty params, P3). How a run resumes after a crash is required, no
1573
- default: rerun (the current
1574
- `run`, args mapped forwards, state migrated; only work since the last state change repeats, so it must be
1575
- idempotent) or abandon (`finish` gets `failed { aborted, reason: "restart" }`); wording aligned with Durable
1576
- (replay-safe, abandon on restart). A recorded outcome resumes only `finish`, never `run`; an abort request is
1577
- persisted. A restart limit as Durable's (owner, 2026-10-27, slice 6b D6): at activation a run recorded `running` was
1578
- cut off by a crash: `restarts + 1`, stored, then it resumes (rerun or abandon); a clean close writes its stopped runs
1579
- back so the next activation counts nothing; a `ctx.state.change` (progress) resets the count; at five in a row the
1580
- run ends with `failed { kind: "restart_limit", restarts }`, `finish` runs, `job_interrupted` is reported (no
1581
- parking, as Durable since #11139). A persisted state document may defer storing a change
1582
- (`ctx.state.change(fn, ctx, { persistence: { kind: "deferred", withinMs? } })`, Durable's shape, default 1,000 ms;
1583
- stored before the outcome is recorded; slice 6b D8).
1584
- - **Chaining:** `finish` may `tx.start` the next job, atomically with the outcome (separate steps, branches).
1585
- - **Not jobs:** request/response work (a method), standing behaviour (a routine), input into running work (a flow,
1586
- §20: the owner's document plus methods), multi-step durable work with sleeps, waits or ownership trees on a host
1587
- with a harness (a Durable task). Jobs as objects (#9) are rejected: a third lifetime, two objects per run for two
1588
- principals, a `finish` across owners.
1589
-
1590
- ---
1591
-
1592
- ## 16. The facet
1593
-
1594
- ```ts
1595
- import { defineFacet } from "@app/core"; // base code's defineFacet, bound to the app's P
1596
-
1597
- export default defineFacet((host, self) => { // `self` (contributions) arrives with slice 8
1598
- self.contribute(Http, { routes: { "GET /notes/export": exportNotes } });
1599
- host.serve(Notes, (params, principal, self) => …);
1600
- host.serve(NoteStore, (params, self) => …);
1601
- });
1602
- ```
1603
-
1604
- - **Facets are typed by the app's principal (owner, 2026-10-21):** base code exports `defineFacet` already bound to its
1605
- `P` (`export const defineFacet = bindFacet<P>()`, next to the principal union), and every facet (server, worker,
1606
- web, TUI) imports it from there; `host.load` accepts only facets typed for the host's `P`, so a factory's `principal`
1607
- narrows by variant. Nothing is checked at runtime: the principal a factory receives is the one the link stamped.
1608
- - A plugin's per-host setup, **declarations only** (owner, 2026-10-26): `host.serve`, `self.contribute` (slice 8),
1609
- `host.references`; no natives, no documents (C16 accepted), no routines, no jobs. Everything a plugin does at runtime
1610
- is done through objects: shared or persisted state and standing behaviour live in a `local` store object with empty
1611
- params (host lifetime, its own failure domain; its dependents park while it is failed and go on when it recovers), as p2 does (its 63 facets take only
1612
- `host`). A facet cannot fail after `load`.
1613
- - `host.serve(Type, factory, { linger? })`: `linger` (milliseconds, 0 by default; slice 3b) keeps a live object with
1614
- params alive that long after its last reference, so a new reference within that time reuses it with its documents
1615
- and dependencies; it never applies to objects that are not live.
1616
- - `host.serve` and contributions are valid only while the setup runs. The facet never `self.get`s a type it serves
1617
- itself.
1618
- - Between plugins only: object types and registries. No natives across plugins except through registry entries.
1619
-
1620
- ---
1621
-
1622
- ## 17. Registries
1623
-
1624
- ```ts
1625
- export const Http = defineRegistry<HttpContribution, Router>("chord.http", { version: 2 }); // shared: identity only
1626
- host.serve(Http, { // the defining plugin's facet: the one provider (slice 8 D1)
1627
- compose: (table, { report }) => buildRouter(table, report), // pure; always delivers a value; reports conflicts
1628
- accepts: { 1: { contribution: (old: HttpContributionV1) => upgrade(old), value: (router) => routerV1(router) } },
1629
- });
1630
- self.contribute(Http, { routes: { … }, wraps: [ … ] });
1631
- const router = self.registry(Http); // a declared dependency; read router.value at use (await host.registry(Http, ctx) outside objects)
1632
- ```
1633
-
1634
- - Each contributor (a facet or an object) contributes **at most one value per registry**; the table is an immutable,
1635
- ordered list of `(contributor, value)`. Contributor order is sorted by plugin name (never load order): deterministic
1636
- on every host and across reloads, and deliberately meaningless; meaningful order comes from the owner's composition
1637
- (e.g. HTTP phases). A reload replaces a contribution as a
1638
- whole.
1639
- - **`compose` is a runtime composition, not a staging check:** contributions can be dynamic (known only once a native
1640
- is open, or changing at runtime; contributions may be readables), so no conflict check can be complete in staging.
1641
- `compose(table, { report })` is pure and runs whenever the table changes (after a commit, when a contributor goes
1642
- live or ends, when a dynamic contribution changes). It always delivers a value with its fallback built in (e.g. the
1643
- first by plugin name wins) and reports conflicts through `report` (owner notices and telemetry events); readers get
1644
- a plain value and never handle conflicts. If `compose` throws, the failure is reported and its
1645
- watches get a `failed` call, while `.value` keeps the last good composition (slice 8), **but only while every
1646
- contribution it was built from is still in the table** (dependency model decision 5, slice 7a): when one leaves (its
1647
- contributor ended, failed or restarted), the last good value is dropped and `.value` throws until `compose`
1648
- succeeds, so it never hands out a native whose contributor ended; only before any good composition, or after such a
1649
- drop, do readers get the error. Work that started earlier keeps the value it read (a pinned Durable phase keeps
1650
- its old table). Helpers: `keyedEntries(table, entriesOf, report)` (a map, the first by plugin name wins, a duplicate
1651
- reported), `orderedEntries(table, itemsOf, orderOf?)`; both keep each item's plugin (named so beside the contracts'
1652
- `keyed`, slice 8 build).
1653
- - **Who contributes (R21):** only facets and host-lifetime objects (`local`, empty params); their factory's `self` has `contribute`, a
1654
- referenced object's `self` does not (a type error). Reading a registry's composed value stays open to every object.
1655
- - **A contribution is in the table exactly while its contributor is live:** a facet's while its plugin is loaded; an
1656
- object's from `live` until it ends, fails or restarts.
1657
- - **The owner decides** conflicts, order and selection (which contributions apply where).
1658
- - **One authoritative declaration (Q8):** only the facet of the plugin that defines a registry declares it to the host
1659
- (`compose`, version, `accepts`); other plugins' tokens only identify it by name and types (contribute and read,
1660
- never bring their own `compose`). A reload of the defining plugin replaces the declaration atomically (`serve`
1661
- replaces; a removed defining plugin's provider goes, its readers wait `not_served`) and the table
1662
- recomposes. Without a declaration (the defining plugin is not loaded) the registry has no composed value: readers
1663
- wait `failed { waiting }` (`unavailable/undeclared`), like a request for a type nobody serves; contributions wait in
1664
- the table.
1665
- - **Versions (Q8, the owner-adapter pattern):** a contribution carries the registry version its plugin was built
1666
- against; older ones are adapted with the defining facet's pure `accepts` when the table is built. A contribution
1667
- without a matching version or adapter (older without adapter, or newer) is left out of the table and reported (an
1668
- owner notice naming plugin, registry and versions); its plugin keeps working. Contributions are in-process values
1669
- (often functions) and are not schema-checked.
1670
- - **Use sites guard contributions:** a contribution is untrusted code (third-party plugins are a goal of p3). Every
1671
- use site catches synchronous throws and rejections when it calls an entry, reports naming the contributor (the
1672
- composed table keeps each entry's plugin name), and continues with the other entries. Durable already does this for
1673
- extensions (`extension_error`; a throwing tool becomes an error result); `compose` reports through `report`.
1674
- - **Slice 8's rules** (decisions "Slice 8 D1" to "Slice 8 S3", `slice-8.md`; S2's `broken` and S3's backoff superseded
1675
- by slice 7a): the token is shared, the provider serves it (`host.serve(R, { compose, accepts })`); `self.registry(R)`
1676
- in a factory is a declared dependency: the attempt parks until the registry has a usable value at its version
1677
- (composed; mapped by `accepts[old].value` for an older reader), otherwise it shows `failed { waiting }` naming the
1678
- registry (`not_served`: `unavailable/undeclared`; `version`: a reader newer than the provider or without a mapping,
1679
- `contract_mismatch`; `compose`: a first `compose` or the mapping threw; `loading` before the publication), woken at
1680
- every change of whether the value is usable; `host.registry` waits the same way up to its `readyTimeout`;
1681
- contributions never fail a registry (a failed one is left out and reported); a throwing `compose` keeps the last
1682
- good composition (above); `retryOn` retries on value calls only; `host.root(fn, context, { principal? })` seals its
1683
- context at settle, abort and `host.close`.
1684
- - **Registries may carry natives.** An entry lives exactly as long as its contributor; consumers look up at each use
1685
- or follow the composed value and keep nothing from an entry beyond a use.
1686
- - **Contributions that change (owner, 2026-10-19; W4):** registries are host-local, so contributions are usually
1687
- in-process values (functions, runtimes, handles). A contribution is fixed for its contributor's life (dynamic parts
1688
- behind handles read at use; a change means a restart or reload), a `Watchable`, or a `NativeWatchable`; Chord follows
1689
- the latter two through the internal flush: on every change it replaces that entry (a new immutable table) and runs
1690
- `compose` again, in the owner's flush, never inside another owner's commit step. The composed value is itself a
1691
- `NativeWatchable`; use sites watch it or read its current value. For in-process values that change,
1692
- `self.writable(initial)` is a `NativeWatchable` with `set` (identity compared, never ops, never a state member):
1693
-
1694
- ```ts
1695
- const ext = self.writable(mcpExtension([])); // e.g. MCP: tools known only at runtime
1696
- self.contribute(HarnessExtensions, ext);
1697
- self.on(mcp.tools, ({ value: tools }) => ext.set(mcpExtension(tools)));
1698
- ```
1699
-
1700
- Tools, sections, hooks, wraps and tasks reach the harness as one Durable `Extension` per plugin contributed to
1701
- p3's core registry; `compose` builds Durable's registry snapshot (Durable applies selection and wraps, and pins a
1702
- snapshot per task phase). Skills and other lists work the same way.
1703
- - **A contribution may be another registry's value** (it is followed: its change recomposes). A ring of registries
1704
- reading each other is caught when one composes (audit A2): a registry read while it composes throws `invalid/cycle`,
1705
- the contribution that read it is left out and reported `contribution_failed`, the rest of the registry works.
1706
- - **Removing a contribution:** there is no remove call (`contribute` is declarative, in the factory). An entry leaves
1707
- the table when its contributor ends, or after a reload whose new code no longer contributes. A live contributor that
1708
- has nothing to offer for now sets its readable to the registry's empty value (an extension without tools, empty
1709
- routes); the table keeps exactly one entry per live contributor.
1710
- - Registries add behaviour (tools, routes, renderers, commands, input gates); they never replace an owner's checks.
1711
- No lifecycle in entries: anything needing cleanup is a native of the contributing object.
1712
-
1713
- ---
1714
-
1715
- ## 18. Start data and platform bindings
1716
-
1717
- There are no host values. Start data (session id, init, data directory) is a `local` object with empty params (host lifetime)
1718
- and constant state (`constant(value)`: a readable that never changes, R23), served by the base code's core facet from the start message:
1719
-
1720
- ```ts
1721
- export const SessionInfo = local("app.session-info", { version: 1, params: {}, members: { init: InitSchema } });
1722
-
1723
- // base code (apps/<app>/src): the core facet, passed to load() like any facet
1724
- export const coreWorkerFacet = (init: Init) => defineFacet((host) => { // base code's own bound defineFacet
1725
- host.serve(SessionInfo, () => ({ init: constant(init) })); // local, empty params: host lifetime
1726
- });
1727
-
1728
- // any plugin
1729
- host.serve(NoteInbox, (_, self) => {
1730
- const info = self.get(SessionInfo, {});
1731
- const watcher = self.open(async (context) =>
1732
- watchDir(join(info.init.value.dataDir, info.init.value.id, "inbox"), { signal: context.abortSignal }), (w) => w.close());
1733
- return {};
1734
- }); // NoteInbox: local, empty params → host lifetime
1735
- ```
1736
-
1737
- Plugins read start data through a reference, after activation (in openers, derives, routines and methods); nothing
1738
- reads it synchronously in a factory. Platform bindings the host owns (a Durable Object's `state` and `env`) are core
1739
- objects whose `self.open` returns the binding and whose `close` does nothing. A long-lived native from the host is a
1740
- host-lifetime object in a core facet (the Durable harness, section 24).
1741
-
1742
- **Core vs. plugin is decided by where the code lives:** base code (`src/`, imported statically by the start code under
1743
- a fixed name such as `@app/core`, not switchable, a change restarts the host) or a plugin directory (found by listing,
1744
- loaded through loader D, named by its `package.json`, switchable, a change reloads it). Core is what the app always
1745
- needs and everything builds on (harness, catalog, access, session location); optional features are plugins (code
1746
- mode is a plugin). Both use exactly the same primitives.
1747
-
1748
- ---
1749
-
1750
- ## 19. Presence
1751
-
1752
- ```ts
1753
- const viewers = self.derive([host.references(Notes)], ([refs]) => refs.length);
1754
- ```
1755
-
1756
- `host.references(Type)` (slice 4b) is a JSON `Watchable` of the references to objects of a type on this host:
1757
- `{ params, principal?, incarnation }[]` (named `origin` until 2026-10-27). It is one rule (owner, 2026-10-24): the incarnation of the host that made
1758
- the reference as its caller sees it, so two tabs are two origins, and a guest's `ctx.get` shows the guest's tab. An
1759
- entry is added when a reference binds and removed when it ends, in that batch; a departure discovered while a batch
1760
- is sending lands in the next batch (so one commit stays one message per link). The host keeps a type's list from its
1761
- first `host.references(Type)` on (one small object per asked type; entries come and go with references). **A link drop is a departure**
1762
- (accurate and simple); smoothing (a phone switching networks) is the UI's job, e.g. a debounced viewer count. Counts
1763
- per person or origin are derived by the app from the principals and origins. There is no consumer-side linger
1764
- (a closed tab closes its link); provider-side `linger` keeps a just-closed object warm and keeps the worker alive
1765
- (section 3). Replaces the presence, viewer and login-abandon leases. "Leaving" is never derived from an unmount
1766
- (section 21).
1767
-
1768
- ---
1769
-
1770
- ## 20. Input into running work
1771
-
1772
- ### Flows kept by their owner
1773
-
1774
- ```ts
1775
- start({ provider }, ctx) → { id } // uuidv7
1776
- LoginFlow {id}: state | { kind: "running"; step?: { id, … }; notices } | { kind: "done" | "failed" | "cancelled"; notices }
1777
- answer({ id, step, value }, ctx) → ok | "step no longer active"
1778
- cancel({ id }, ctx)
1779
- ```
1780
-
1781
- The UI watches the state; a late or second answer to a step that is gone is refused; a promise-based callback (pi-ai's
1782
- `prompt`) stays inside the owner (its job keeps the resolver). Imperative consumers (tests, scripts, a CLI, an agent
1783
- tool) use a generic client helper over the same state, not a second protocol:
1784
-
1785
- ```ts
1786
- async function* steps(flow, ctx) {
1787
- let last = 0;
1788
- for (;;) {
1789
- const s = await until(flow.state, (v) => v.kind !== "running" || (v.step && v.step.id > last), ctx);
1790
- if (s.kind !== "running") return s.kind;
1791
- last = s.step.id;
1792
- yield s.step;
1793
- }
1794
- }
1795
- for await (const step of steps(await ctx.get(LoginFlow, { id }), ctx))
1796
- await login.answer({ id, step: step.id, value: answerFor(step) }, ctx);
1797
- ```
1798
-
1799
- A long-held server `step()` call is not used: a link drop fails it and the consumer cannot tell whether it missed a
1800
- step; state re-holds by itself and `last` keeps steps from being lost or repeated.
1801
-
1802
- ### The Questions service
1803
-
1804
- Another pattern (`apps/p2/docs/questions.md`): a shared store with per-principal views (asker: `ask`; viewer: `open`,
1805
- `answer`), typed questions (`text`, `select`, `confirm`), policies over a live audience (`first`, `quorum`, `all`),
1806
- reattachment by `key`, deadlines, authorization per question, secrets redacted. Fits tool approval and a question the
1807
- agent asks everyone present. Its store must live in an object (it predates "natives only in objects").
1808
-
1809
- > **Decision needed: where a flow lives.** Options: (a) a keyed document of its owner; (b) an object `LoginFlow {id}`
1810
- > living until done. (Jobs as objects were rejected, §15; a flow kept as its owner's document plus a job is the likely
1811
- > answer.)
1812
-
1813
- ---
1814
-
1815
- ## 21. Reload and rollout
1816
-
1817
- ### Per host
1818
-
1819
- `host.reload(facets, context)` (slice 7b; decision "Slice 7b's open points, as recommended" (1)) takes the host's
1820
- **complete new plugin set** after `load`: a plugin in it and not loaded is added; one loaded with another facet value is
1821
- changed (Chord compares no code); one passed as the very same facet object is unchanged and untouched (owner,
1822
- 2026-10-29: base code passes its core facet value every time); one loaded and not in it is removed. It resolves with a
1823
- report once the commit happened and every object took its fate (swaps and retries had their first dependency check;
1824
- it does not wait for objects to go live); a plugin whose new code fails keeps its old code and is listed in the
1825
- report's `failed` (per plugin, below).
1826
- Reloads run one after another per host; before `load` resolved it throws, after `close` it rejects `released/closed`;
1827
- `context` bounds it (decision 4: no install watchdog): its abort before the commit rejects `aborted` and changes
1828
- nothing, after the commit it only ends the wait: it rejects `aborted` with `details.committed`, a `CommittedReload`
1829
- `{ added, changed, removed, failed }` naming what the commit applied (the plugins component adopts it, so a later
1830
- reload never passes a committed plugin's old facet; owner, 2026-10-30).
1831
-
1832
- ```ts
1833
- type ReloadReport = {
1834
- readonly plugins: { readonly added: readonly string[]; readonly changed: readonly string[]; readonly removed: readonly string[] };
1835
- readonly failed: readonly { readonly plugin: string; readonly error: unknown }[]; // new code failed: old code kept, an added one left out
1836
- readonly objects: readonly ({ readonly object: string } & (
1837
- | { readonly kind: "swapped" } | { readonly kind: "restarted" } | { readonly kind: "ended" }
1838
- | { readonly kind: "parked"; readonly cause: FailureCause } | { readonly kind: "retried" }))[];
1839
- };
1840
- ```
1841
-
1842
- ```
1843
- 1. load new bundles (the app's or loader's: a facet arrives evaluated); a plugin whose build or evaluation
1844
- fails keeps its loaded facet (`reload(facets, context, { failed })`)
1845
- 2. staging every new setup into a staged table, and every affected object's new factory against a recording
1846
- `self` (declarations only, nothing activated, bound or opened); a plugin whose new code throws keeps its
1847
- old code, staging runs again without it, then the closure rule (below)
1848
- 3. commit one batch: the host switches to the new code atomically, a publication (7a)
1849
- 4. after each object takes its fate (below)
1850
- ```
1851
-
1852
- - **Per plugin, never all or nothing** (owner, 2026-10-30, decision "Per plugin at startup and reload"; supersedes 7b's
1853
- rollback per host): a plugin whose new code fails at a reload (its build or evaluation, a setup's or factory's throw
1854
- in staging, a declaration error, `checkAccepts`, a type or registry served twice, a remote type on a host without
1855
- principal or address) keeps its old code (its loaded facet, unchanged) and is reported in the reload's report
1856
- (`failed: [{ plugin, error }]`, the same list `load`'s report has; an added plugin that fails is left out); staging runs again without it, and every other plugin of the reload applies. **The
1857
- closure rule:** a changed plugin whose recorded requests would not bind because the plugin they need was kept old (or
1858
- is missing) is kept old too, so a consumer edited together with a broken provider keeps working on its old code. At
1859
- startup the same holds: `load` leaves a failing plugin out and resolves with `{ failed: [{ plugin, error }] }`; its
1860
- consumers wait `failed { waiting }`; `load` never closes the host for a plugin (base code decides whether its core
1861
- failing is fatal). A loader that kept a plugin on its loaded facet because its new code failed before staging (its
1862
- build, its evaluation) tells the host with `reload(facets, context, { failed })`: the host lists it and applies the
1863
- closure rule to it as to a plugin whose staging failed. What no rule detects: a consumer relying on new behaviour of a kept provider whose contract did not
1864
- change (as in a rollout across hosts). Runtime states (registry conflicts, failed opens, migrations) stay per object
1865
- after the commit (`onError` as always).
1866
- - **Staging** runs every new setup (each plugin into its own table, merged; an unchanged or kept plugin's loaded
1867
- entries are reused, its setup not run again) into a staged table beside the live one (types with their factory,
1868
- `linger` and provider, `bindProvider(contract, options.accepts)`; registry providers; facet contributions by
1869
- plugin), then, for
1870
- every live, activating, parked or failed object of a changed or removed plugin whose type is still served, its new
1871
- factory with the object's params (and principal) against a recording `self`: it records what the factory opens,
1872
- the documents, tables and jobs it declares with their versions, its contributions and requests, runs the checks an
1873
- attempt makes without effects (declared twice; persisted data outside a stable identity; contributions outside a
1874
- host-lifetime object; a document or job at an older version, or at its version with another schema), and hands out
1875
- inert handles. Staging is synchronous, so no request or arriving hold meets it half done (audit A1: model §1's
1876
- `installing` is cut).
1877
- - **The commit** (one batch): the served types become the staged ones (an unchanged plugin's entries stay as they
1878
- are); a removed plugin's registry provider goes (its readers wait `not_served`), a reloaded one's replaces the old
1879
- (`RegistryRecord.serve` replaces), the reloaded plugins' facet contributions are replaced by plugin (object
1880
- contributions follow their objects), every changed registry composes once; a removed type's presence list goes.
1881
- After the batch, each object takes its fate, host-lifetime objects of new types start (no barrier), and the
1882
- publication wakes the requests indexed under the names the reload serves (`UnboundIndex.wake(names)`, per name),
1883
- refused holds of those names re-run their start.
1884
- - **Fates** (decided in staging; objects of plugins not in the reload are untouched):
1885
-
1886
- | The object | Fate |
1887
- | --- | --- |
1888
- | its type is removed | **ended**: as an end (natives close `end`, callers of running calls rejected `released`, handlers drained, in-memory documents gone, persisted ones kept); its holders' requests are not ended: they wait unbound `not_served` (§7) |
1889
- | failed, parked, activating or waiting for its backoff | **retried** on the new code (`ref.retry()`'s rule, whatever broke it); an activating attempt is sealed and its natives close `reload` |
1890
- | live, neither its live attempt nor the new factory opens natives, and no table of the new factory is newer than the store's | **swapped** in place (below) |
1891
- | live, otherwise | **restarted**: new calls park (it shows `loading`), its contributions leave, running calls drain (bounded by `closeTimeout`; a call outliving the drain is cut off by the seal fence), the attempt is sealed (in-memory job runs end `aborted { reload }`, persisted ones are stopped and resumed, R3), natives close `reload`, the new attempt activates after that teardown (documents stay; eager table migrations run as at activation) |
1892
- | any of the above whose new code waits for a dependency | **parked** (decision 4): no overlap of old and new code; reported with the cause |
1893
-
1894
- A restarted object gets a new instance id (an old activation chain never matches it); a swapped one keeps it; a
1895
- retried one keeps it as any retry does. Cycles are checked again for the new attempts; `parked_long` is unchanged.
1896
- - **The pure swap** (decision "The seal fence": not a replacement while its calls run): a new attempt of the same
1897
- object (its documents, line and job records) activates at once; calls arriving meanwhile wait at
1898
- the gate (bounded by `readyTimeout`, `unavailable/park_timeout`). The new attempt's requests are made and bound
1899
- before the old attempt's are released (a request equal to an old one binds to the same target with no gap, M§3.9).
1900
- Running calls finish on the old attempt with its handles valid, except R15: an old call touching a document whose
1901
- version rose throws once (`released/version`), the document intact, the call not resent; the same for a table whose
1902
- version rose (old table handles' version fence: old code never issues SQL for a dropped column). Once the swap
1903
- ended (the new attempt live, parked or failed) and the old attempt's calls settled (bounded by `closeTimeout`,
1904
- `drain_timeout`), the old attempt is sealed and its references released; its job invocations finish on their old
1905
- code. Retiring attempts are bounded by `closeTimeout` each; a later swap never waits for them (several may retire
1906
- at once after quick reloads), while a restart, an end and the host's close do (an end rejects their callers at
1907
- once). The references move to the new instance's members by name (one frame from the last value; a member the new
1908
- variant lacks fails `invalid/member`; §7); exposed derives are matched by their member names, internal ones are
1909
- rebuilt; in-memory documents migrate through `migrate` when the new code declares a higher version; the
1910
- contributions are replaced in one batch; `self.writable` starts at its new initial value (decision 2); `retryOn`
1911
- sources are re-declared. **Routines hand over per object:** the old attempt's routines are aborted; the new ones
1912
- start once the old routine calls finished, bounded by `closeTimeout` (a stuck one is reported `drain_timeout` and
1913
- the whole old attempt is sealed then, audit A12: one seal token per attempt); calls never wait.
1914
- - **Natives are not kept across reloads by name:** natives have no line, transactions or schema, so old and new code
1915
- would interleave unchecked. In practice a restart costs little (the Durable harness is base code, terminal PTYs live
1916
- in their own process, model runtimes, sandboxes and the search index rebuild in milliseconds); reloading the plugin
1917
- that owns SSH connections or the relay socket hurts.
1918
- - **No factory trial, no migrate dry run, no consumer contract check during staging:** staging records declarations;
1919
- incompatible consumers wait at bind (`failed { waiting }`, `contract_mismatch`). The one exception is the closure
1920
- rule above: when a plugin of the reload failed, a changed plugin's recorded requests are checked as a bind would
1921
- check them, to keep it old.
1922
- - **Start barrier** (host start and first load; dependency model §6, decision (a), slice 7a): `load` runs the facets'
1923
- setups (the core facet with its start data among them) and **publishes** them in one batch (types served,
1924
- registries served and composed once, contributions in their tables); requests that waited for the publication are
1925
- placed after that batch (holds and `host.hold` wait for the publication only, never for the barrier: two hosts
1926
- whose objects need each other's types start without a deadlock). Then it activates the host-lifetime objects and
1927
- resolves when each has its **first outcome**: live, failed by its own cause, or parked with no blocker that is a
1928
- local object still without its first outcome (`local`: executing on this host, a keyed pin still loading here
1929
- included; a wait on another host or on a failed dependency ends the first pass), or ended (`host.close` settles a
1930
- waiting `load`). One first-outcome signal per object, separate from the readiness dependents wait for, counted once,
1931
- never reopened by retries. So `CodeMode → Harness` waits for the harness's outcome. **What it promises:** every
1932
- host-lifetime object here had its first try, and the contributions of those that went live are in their tables;
1933
- **not** every tool that will arrive (a parked or slow contributor, tools found in `onLive`, MCP): what a first turn
1934
- needs is p3's explicit admission check. Base code calls `harness.resume()` after `load` (the harness is an ordinary
1935
- host-lifetime object that opened Durable paused during the barrier; owner, 2026-10-21, refines R17). Nothing waits
1936
- for specific contributions: what is missing shows where it is used (section 24). Failed plugins are reported with
1937
- their error. Reloads need no barrier.
1938
-
1939
- ### Rollout across hosts
1940
-
1941
- - **The rollout is the app's** (decision "Slice 7b's open points" (3)): it calls `host.reload` on each host in order,
1942
- server, then workers, then clients; Chord guarantees per host (staging, commit, a failing plugin kept on its old
1943
- code). The plugins component's `rollout` (slice 7c) runs such steps. An install never waits for activations (a reverse-order rollout would
1944
- deadlock).
1945
- - **Each host knows only its own install** (model §5): until its reload commits (while the app bundles, before
1946
- `host.reload`), a hold that does not fit its running code is answered `failed { waiting, version }` and the commit
1947
- wakes it (a blip of at most one install; staging itself is synchronous, audit A1). What a consumer on
1948
- another host sees follows §7: kept and freshly bound while its version is accepted; `failed
1949
- { waiting }` (`version`, `not_served`) otherwise, bound again by the install that serves it; a consumer whose own
1950
- code moves to a new version releases its old request and makes a new one.
1951
- - **The app's loader keeps its own duties:** the desired code set, a digest over the facet bundles' content hashes (an
1952
- unchanged server restart reinstalls nothing), serialized installs, a host that starts or reconnects installing the
1953
- current set before anything is routed to it, a rejected own install failing its own requests with the reason.
1954
-
1955
- ### Loading plugins and the reload loop (slice 7c)
1956
-
1957
- - **No dev/prod split** (owner, 2026-10-30): a Chord app is self-modifying (the owner or an agent edits a plugin while
1958
- it runs), so finding, building, loading, watching and rolling out plugins is core machinery: one component,
1959
- `chord/next/plugins` (`src/next-node/plugins/`, Node-side; the kernel stays portable and takes facets however they
1960
- were made: static imports in tests and Durable Objects work the same). Reloads stay explicit: the watcher marks,
1961
- never applies.
1962
- - **A plugin** is a directory with a `package.json` (its `name` is the plugin's name, npm style) and one file per facet
1963
- kind the app names; plugins come from roots found by directory listing (no source parsing; the first root wins a
1964
- duplicate name). Dependencies between plugins resolve by contract name at runtime; names are prefixed
1965
- (`<plugin>.<name>`; tools `<plugin>_<name>`). A plugin carries the contracts it was written against (decision "Contracts come from where the
1966
- plugin's code came from"): plugins that change together import each other by relative path within a root
1967
- (copied into the importer's script); others take contracts as an npm dependency at a fixed version (slice 10 still
1968
- resolves imports by plugin name; the plugin slice changes it).
1969
- - **Loader D:** one esbuild script per facet (its own files, copied files of other plugins, its npm `dependencies`
1970
- inlined; host packages, `chord.external` packages and Node builtins external, passed in at evaluation); each facet kind is defined once, `kinds: { <kind>: { platform: "node" | "browser", hostPackages } }` (slice 11); evaluated with
1971
- `vm.Script` under a stable filename per (plugin, kind, digest); no module map: old generations are reclaimed by the
1972
- GC; V8's compilation cache turned off when the component is created. `pluginFile(path)` resolves a file of the
1973
- calling facet's own plugin. A plugin's dependencies are installed into its directory (`installDependencies`, as
1974
- coding-agent does: `--omit=dev --legacy-peer-deps --ignore-scripts`). esbuild is an optional peer dependency.
1975
- - **The reload loop:** a watcher marks plugins dirty from the files each facet used (a copied contract dirties every
1976
- user) and flags changes of base code (the app restarts its hosts); a build is per plugin (a failed one keeps its old code); `rollout` runs the app's
1977
- steps in order (server, workers, clients; decision "Slice 7b's open points" (3)). A reload control (a button, a CLI,
1978
- an agent tool) is the app's. One base bundle per surface (host packages and the app runtime) is an app's startup
1979
- optimization, the web's in slice 11.
1980
- - Project plugins, trust, snapshots, scopes and npm/git package installs: `apps/p2/docs/plugin-loading.md` (still the
1981
- reference for those; not in 7c).
1982
-
1983
- - **UI reload vs. leaving:** "leaving" is never derived from an unmount, only from explicit navigation or presence (a
1984
- dropped reference); a component unmounted by a reload has not left.
1985
-
1986
- > **Decision needed: project plugins.** Per-directory plugins with trust and snapshots (`plugin-loading.md`) need their
1987
- > own pass over this design.
1988
-
1989
- ---
1990
-
1991
- ## 22. Wire
1992
-
1993
- Exposed documents, derives and readables are state members: a snapshot in `bound` when a hold binds, ops per commit
1994
- (a draft's recorded ops, no diff), ops from diffs for derives, ops of job state documents (slice 5), and failed
1995
- members in the entry of the message that carries them. **Commits are atomic for consumers:** locally, subscribers are
1996
- notified once after every document of the commit is adopted; remotely, one `state` message per commit per link and
1997
- origin carries an entry per touched hold, applied in one batch before listeners run (also when one Durable commit
1998
- touches several holds), so remote consumers never see a torn commit. Consumers apply ops with `applyImmutable`: no
1999
- validation, no clone of snapshots or ops.
2000
-
2001
- - **The protocol version** travels in `hello`; hosts of different versions refuse each other (a web page reloads for
2002
- a newer server). Error reasons and message kinds are part of it. Until p3 ships, changes keep `PROTOCOL_VERSION` 1
2003
- (nothing is deployed); after that every message or reason change bumps it.
2004
- - **One typed `Message`** (owner, 2026-10-22, "Wire protocol"): a pi-schema schema `MESSAGE`, a tagged union over
2005
- `kind`, from which the protocol types derive; every decoded message is checked against it (compiled once) unless
2006
- the link is trusted (section 3). Kinds:
2007
-
2008
- | Kind | Direction | Fields |
2009
- | --- | --- | --- |
2010
- | `hello` | both, first | `protocol`, `incarnation`, `calls` (the call window N) |
2011
- | `hold` | to provider | `origin?`, `hold`, `type`, `version`, `fingerprint`, `params` (part), `address`, `principal?`, `incarnation?`, `chain?` (activation chain, Q5), `limit?` (decoded size limit, 4b) |
2012
- | `revoke` | parent to child (route link) | the revocation value (4b) |
2013
- | `release` | to provider | `origin?`, `hold` |
2014
- | `retry` | to provider | `origin?`, `hold`, `hops` (the retry's hop budget, 1-16: 16 from the first host, one less for each host it passes on from, none sent at 0; audit A5); relays forward it unchanged |
2015
- | `call` | to provider | `origin?`, `call`, `hold`, `method` (index), `args?` (part; absent: no arguments), `segments?` |
2016
- | `abort` | to provider | `origin?`, `call` (named `cancel` until 2026-10-27) |
2017
- | `ack` | to provider | `origin?`; one per applied `bound`/`state` message |
2018
- | `closed` | relay to provider | `origin`: the downstream origin ended |
2019
- | `bound` | to consumer | `origin?`, `holds: [{ hold, variant, members: [{ member, value }], failed }]`; one batch |
2020
- | `state` | to consumer | `origin?`, `holds: [{ hold, members: [{ member, ops }], failed, retired }]`; one batch (`retired`: members retired since the last message, slice 6a) |
2021
- | `failed` | to consumer | `origin?`, `hold`, `cause { kind, error }` (`kind`: `transient`, `broken` or `waiting`, slice 7a), `retryIn?` (a transient cause's backoff; absent: broken, waiting); each new cause of a parked object is a message of its own |
2022
- | `loading` | to consumer | `origin?`, `hold`: a new attempt after a failure, or a relay's upstream dropped |
2023
- | `result` | to consumer | `origin?`, `call`, `value?` (part; absent: `null`), `segments?` |
2024
- | `error` | to consumer | `origin?`, `call`, `error` (a ChordError's JSON or a plugin's code, message, details) |
2025
- | `gone` | to consumer | `origin?`, `hold`, `error`: the held object ended (revocation 4b; a reload never ends a hold, it unbinds it with `failed`, slice 7b; relays never make one) |
2026
- | `ping`, `pong` | both | the heartbeat |
2027
-
2028
- A `bound` on a hold that is bound already replaces its replicas in one batch, another variant allowed (re-holds,
2029
- slice 7b's restarted objects and its swaps to another variant).
2030
- - **Codecs are pluggable per link** (both ends use the same): `binaryCodec` (default: a kind byte with a flag for a
2031
- following origin varint, varints, raw incarnations and fingerprints, length-prefixed strings and parts; about 23 B
2032
- for a streamed token) and `textCodec` (Delta-style JSON tuples without field names, a message with an origin wrapped
2033
- as `["@", origin, tuple]`; for debugging; `describeMessage` prints any message so). Measured: a 2,000-token reply
2034
- about 46 KiB instead of 196 KiB. No CBOR (revisit only if benchmarks show encoding as a bottleneck).
2035
- - **Parts are opaque** (slice 4a): `params`, `args`, `value`, snapshot values and ops are a `Part` (JSON text at the
2036
- origin, its UTF-8 bytes once a binary codec received it). A part is parsed only where it is owned, right when its
2037
- message is handled (the provider parses params and arguments, the consumer results, snapshots and ops), so a relay
2038
- forwards it unparsed and a malformed part is still a protocol error. A message naming an unknown id is ignored
2039
- before its parts are parsed. The text codec re-serializes parts at decode (one parse per part per hop, accepted for
2040
- a debugging codec).
2041
- - **Names travel as indexes** into the hold's bound version (each variant's state members and methods sorted; variants
2042
- sorted). A reload that no longer accepts that version unbinds its holds first (`failed { waiting }`, slice 7b).
2043
- - **Checks by layer:** the codec's structural decode, the `MESSAGE` envelope (skipped on trusted links), the bound
2044
- version (ids, indexes, order), then the owners (`checkParams`, `checkArgs`, Delta's decoder).
2045
- - **Unknown ids are ignored on both sides (Q1):** they are normal races (a `result` crossing an `abort`, a `call`
2046
- crossing `gone`, a state part crossing a `release`); the side that ended a hold or call settles its own pending work
2047
- (a consumer receiving `gone(h)` rejects its pending calls on `h`; per-direction order guarantees nothing else for `h`
2048
- follows). Protocol errors close the link and are reported (`protocol_error`): a message failing the schema or the
2049
- codec, a malformed part, a reused live id, more than N running calls of one origin, a broken handshake (a first
2050
- message that is no `hello` of the link's codec, a second `hello`, another protocol version).
2051
- - **Byte segments:** a payload (arguments, a result) whose method's schema has a `bytes()` leaf carries each
2052
- `Uint8Array` as a raw segment referenced by `{"$bytes": i}` and read back as a view of the received message; `$bytes`
2053
- is the one reserved key there (`invalid/args`). Never base64. State is JSON only.
2054
- - **Encoders:** each member of a hold has its own Delta encoder and decoder (path interning end to end between
2055
- provider and consumer), restarted with every snapshot. Two holds of the same principal (two tabs) encode the same
2056
- ops separately (O(change) each). A part is encoded once at its origin; relays never re-encode it.
2057
- - **Sending:** one `state` message per commit per link and origin while the window has a slot; otherwise the ops wait
2058
- in the members' pending queues and leave as one message when an `ack` frees a slot (section 3).
2059
- - **Relays** read and rewrite only envelopes (section 3, "Relays").
2060
- - **Size limits per part (R2, Q2; slice 4b):** limits apply to each part (wire and decoded size), configurable per
2061
- link, checked from the part's length before it is parsed or inflated; the decoded limit is enforced in the one
2062
- decode function. An oversized part fails only its own hold or call (`too_large/part`); the other parts of the message
2063
- apply; a snapshot over the limit fails its hold with no automatic re-hold. The decoded limit travels with relayed
2064
- work: the relay checks the admitting link's wire limit itself and stamps its decoded limit on the upstream `hold`
2065
- (honoured on the parent link only, never taken from a client; calls inherit their hold's), and the host that
2066
- inflates enforces the smaller of its own and the stamped one while inflating, after the part's owner and id are
2067
- known (parts for unknown ids are never inflated, Q1). A relay checks only what arrives from downstream; answers
2068
- from upstream (the app's own workers) it forwards unchecked and unparsed, and the end that parses them checks them
2069
- against its own link's limits (owner, 2026-10-24: each end checks what it parses; a relay check needed a re-hold
2070
- with the same id, which old messages in flight could mistake for the new hold). So IPC carries no limit of its own.
2071
- A reference failed `too_large/part` is never held again automatically: it leaves its path, so a reconnect does not
2072
- hold it; only `ref.retry()` puts it back (a new hold). This lives only in the consumer's memory, as long as the
2073
- reference. The
2074
- WebSocket's `maxPayload` stays only the transport's hard cap (e.g. 64 MiB; code 1009 closes the connection).
2075
- Defaults for client WebSockets: 16 MiB on the wire and 64 MiB decoded per part; none on IPC.
2076
- - **Compression at the origin** (owner, 2026-10-19; slice 4b): a JSON part above a threshold (e.g. 16 KiB) is
2077
- compressed once by a host with a synchronous compressor when it encodes it (`createHost({ compression })`, Node's
2078
- zlib adapter in a Node-only subpath), whatever the link (IPC included), only if it shrinks; hold params are never
2079
- compressed; byte segments stay raw; the codec is in the part's envelope (the text codec tags every part, so no JSON
2080
- value is reserved); relays forward it compressed; the end that owns it inflates it. Option (b) (owner, 2026-10-24):
2081
- hosts without a compressor (browsers) send uncompressed and inflate asynchronously (`DecompressionStream`), holding
2082
- later messages of that link in order (bounded by the window and N; acks go out after apply). **Child links refuse
2083
- compressed parts** (protocol error): honest clients never send them, and a 65 KB part could inflate to 64 MiB on the
2084
- server; so asynchronous inflate happens only on a host receiving from its parent or a route. Because a host cannot
2085
- tell whether its parent sees it as a child (a tab) or over a route (a worker), call arguments sent up a parent link
2086
- are never compressed; results and state going up are. Compressed hold params are a protocol error on every link.
2087
- The asynchronous inflate runs one part at a time; the queue behind it is bounded by the sending peer's window and N,
2088
- so only a misbehaving parent or route peer could grow it (accepted: those are the app's own hosts). The adapter reports "too large"
2089
- and "corrupt" as a tagged result. Limits and the threshold count bytes. No per-link compression.
2090
- - **Trace carriers (R5; slice 9)** are an optional bounded field of `call` and `hold` (key count, string lengths);
2091
- relays read them from the envelope.
2092
- - **Adapted bindings get diffs** (slice 7b; decision "References are the only indirection" (5)): a consumer bound
2093
- through `accepts` attaches to the object instance's shared mapping for its version: per member one derive of the
2094
- instance's member through `(current) => old` (a changed member), of its whole state (a removed member), or the
2095
- member itself (unchanged), made on first use, dropped when no reference of that version is left, gone with the
2096
- instance; one map and one diff per commit per version whatever the number of old references, each hold encoding its
2097
- own ops, so an old tab never receives a large state whole on every commit. A new instance (a reload) has its own
2098
- mappings; the references move to them as to any new instance (one frame, never a new mapping applied to the old
2099
- instance's values). A version the instance does not accept gives no member: the reference waits unbound with its
2100
- last values.
2101
- - **A `failed` on a bound hold unbinds it** (slice 7b, model §5): the consumer applies it as a start-over plus the
2102
- failure (its calls waiting for a slot reject with it; the provider rejects its calls in flight once); the provider
2103
- detaches the hold's sources, drops its unsent pending ops and a queued `bound`, and keeps the ack slots of `bound`
2104
- and `state` messages already sent until their `ack` or the link's loss. A reload sends it when the object's type is
2105
- removed (`not_served`), its version is no longer accepted (`version`), or a swap parks on a failed dependency; a
2106
- restart or a parked swap still loading sends `loading`; both are followed by a fresh `bound` when the object is live
2107
- again (applied as a re-binding). A swap in place keeps the hold bound and sends it a fresh `bound` once the new
2108
- instance is live (audit A9, 2026-10-30: one rebind path; a tab's watchers may get a frame for an unchanged member).
2109
-
2110
- ---
2111
-
2112
- ## 23. Optional components
2113
-
2114
- The app kit's Node components (slice 10, `slice-10.md`, decision "Slice 10's points"): `chord/next/http` and
2115
- `chord/next/workers` in `src/next-node/`; the web page host and the TUI are slice 11. Each is ordinary code on Chord's
2116
- public API; nothing in the kernel depends on them.
2117
-
2118
- ### HTTP (`@earendil-works/chord/next/http`)
2119
-
2120
- The core is one Web-standard handler built from the registry `Http` (decision "The HTTP core is a fetch handler"):
2121
-
2122
- ```ts
2123
- const http = createHttp(server, { // settings are arguments, fixed for the component's life
2124
- listen: { host: "127.0.0.1", port: 8788 }, // Chord's own Node listener; none: the app mounts `fetch`
2125
- links: { path: "/chord", options: (request, principal) => ({ limits, maxPayload }) },
2126
- closeTimeout: 30_000,
2127
- onError, // HttpError
2128
- }, ctx);
2129
- await plugins.load(server, { kind: "server", core: [{ name: "chord.http", facet: http.facet }, appCore], modules }, ctx);
2130
- // an app with its own server: hono.all("/*", (c) => http.fetch(c.req.raw, { localAddress, localPort, remoteAddress }))
2131
- // plain Node: nodeRequest(message, res) converts with the listener's checks; server.on("upgrade", http.upgrade)
2132
- await http.close(ctx); // before host.close: drains running requests
2133
- ```
2134
-
2135
- - **The facet** (plugin `chord.http`, passed as the same object at every reload) serves the registries `Http`
2136
- (`compose` builds the router) and `Authenticators`, and with `listen` the listener: a host-lifetime object whose
2137
- native is Chord's Node server, opened right after `load`'s publication, so a reload never closes it (decisions "The
2138
- HTTP server is a native object", "Settings are arguments, extensions are registries"). `fetch` resolves the
2139
- registries once; requests before the publication wait (503 past `readyTimeout`).
2140
- - **Contributions to `Http`:** `{ routes?, wraps?, sockets?, maxPayload?, hosts?, framers?, relays?, csp? }`, a value
2141
- or a writable (a change recomposes the router). A request uses the router as it was when it started.
2142
- - **The security baseline** (decision "The HTTP component's security baseline", on for every request and upgrade
2143
- before any plugin code): (1) **provenance**: local only when the connection's local address is loopback, `Host` is
2144
- a loopback name with the port and no `Forwarded`/`X-Forwarded-*` header; a forwarded request on loopback only
2145
- through a contributed relay whose `verify` names its origin (`{ kind: "relayed", relay, origin }`); otherwise only a
2146
- contributed host (https); duplicate or missing `Host`, userinfo in it, absolute-form targets: 403; an unparsable
2147
- target 400; `TRACE`, `TRACK`, `CONNECT` 501 (a route for them is refused at compose). A mounted handler without
2148
- `localAddress` and `localPort` is never local. (2) **Foreign requests** (Fetch Metadata) never reach the
2149
- authenticators: anonymous, except a top-level `GET` navigation to a `page: true` route. (3) A foreign `Origin` is
2150
- 403; an unsafe method from a browser needs the app's own `Origin`; a `crossSite: true` route opts out and always
2151
- runs anonymous. (4) **Default headers** on every answer, the component's own included: `no-store`, `nosniff`,
2152
- `no-referrer`, `X-Frame-Options: DENY` (without framers), a CSP (`default-src 'none'`, scripts `'self'` and a
2153
- per-response nonce `request.nonce`, `connect-src` self and its WebSocket, `frame-ancestors` the framers or
2154
- `'none'`, plus contributed `csp` sources); a response's own headers replace same-named ones. (5) `cookie(name,
2155
- value, { secret, request, sameSite?, maxAge? })` and `readCookie(request, name, secret)`: `HttpOnly`, `Path=/`,
2156
- `SameSite=Strict` or `Lax`, `Secure` on a remote origin, value and expiry signed. (6) `bytes` refuse foreign
2157
- requests, are attachments unless `inline` (then with a `sandbox` CSP), download names stripped of control and
2158
- bidirectional characters.
2159
- - **Who:** the `Authenticators` registry, in contributor order (an app needing precedence contributes one that
2160
- decides); the first principal wins, a throwing one is reported and skipped, none: anonymous. They run raced against
2161
- the request's signal and stop once it aborts. Who someone is stays app policy (D3); the registry replaces D3's
2162
- single function so plugins (a device pairing, a share) can add credentials.
2163
- - **A request's scope:** one `host.root` with its principal (an explicit `undefined`: anonymous; an anonymous scope
2164
- gets no remote object served here, `forbidden` → 403) spans matching, wraps, the route and the response until its
2165
- body is written or abandoned; its signal aborts on disconnect. `HttpRequest`: `method`, `path`, `params`, `query`,
2166
- `headers`, `origin`, `provenance`, `nonce`, `json(limit?)` (1 MiB; 400, 413), `body(limit?)`.
2167
- - **Patterns** (D8): exact segments, `:name`, a trailing `/*`; decoded segments with `/`, `\`, NUL, `.` or `..` are
2168
- 400; the most specific match wins segment by segment; a pattern from two contributions is a reported conflict, the
2169
- first by plugin name wins; `HEAD` falls back to `GET`; no route: 404. A route is a function or `{ handler, page?,
2170
- crossSite? }`. Wraps (D2) as below.
2171
-
2172
- ```ts
2173
- type HttpResponse = { readonly headers?: Readonly<Record<string, string | readonly string[]>> } & ( // D5
2174
- | { kind: "json"; value: JsonValue; status?: number } | { kind: "html"; body: string; status?: number }
2175
- | { kind: "bytes"; mime: string; size?: number; read(offset, length, ctx): Promise<Uint8Array>; download?: string; inline?: true; ranges?: boolean }
2176
- | { kind: "redirect"; to: string; status?: 302 | 303 | 307 } | { kind: "error"; status: number; message?: string });
2177
- ```
2178
-
2179
- `bytes` are pulled in 256 KiB reads as the consumer reads (ranges 206/416, `HEAD`, chunked without `size`, R6); no
2180
- read starts once the request's scope is sealed; a short or throwing read destroys the connection. 204, 205 and 304
2181
- carry no body. `fileResponse(path, { download?, inline?, ranges?, mime?, root? })` stats at once (missing: 404; with
2182
- `root`, a real path outside it: 403), opens its handle at the first read, closes it when the scope seals. A throwing
2183
- route or wrap is a 500 without its message.
2184
-
2185
- ```ts
2186
- type Wrap = {
2187
- name: string;
2188
- phase: "observe" | "headers" | "transform"; // the component's phases, outermost first
2189
- scope?: "own" | "all"; // default "own": only this contributor's routes
2190
- route?: string; // only this route; a missing route is a reported conflict
2191
- wrap: (req, next, ctx) => Promise<HttpResponse>;
2192
- };
2193
- ```
2194
-
2195
- Wraps (D2) run within a phase in contributor order (no numeric priorities: plugins have no single registration
2196
- order; Fastify's lifecycle phases and encapsulation are the model). Wraps may add a security boundary on top of a
2197
- route's checks, never instead of them.
2198
-
2199
- - **Sockets** (D6): `sockets: { "/terminal/:id": (socket, request, ctx) => … }`, a `ws` WebSocket after admission
2200
- and the authenticators (no principal: 403 before plugin code), `maxPayload` per contribution (1 MiB), pinged after
2201
- 15 s of silence and terminated 15 s later. **Links:** `links.path` upgrades to `host.accept(webSocketLink(socket), {
2202
- principal, limits })`; a client that stops reading is cut off past 4 MiB waiting. **What is removed is closed at
2203
- once** (decisions Q6, "allowed hosts only through contributions"): a link or socket whose host, relay or socket
2204
- handler leaves the router is terminated and its scope sealed; an upgrade is checked again against the current router
2205
- after its authenticators answered.
2206
- - **`close(ctx)`:** new requests and upgrades refused (503), sockets and links closed (1001, terminated at
2207
- `closeTimeout`), running requests waited for up to `closeTimeout`, then sealed; before `host.close`.
2208
- - **Cost** (decision "a route's overhead accepted"): +20-21 µs per request over a plain Node handler (standard bench),
2209
- +12-13 µs warmed. `ws` is an optional peer dependency (D7).
2210
-
2211
- ### Workers (`@earendil-works/chord/next/workers`)
2212
-
2213
- `createWorkers(host, Kind, { kind, entry, execArgv?, env?, authorize, principal, start, lock, idleMs?, plugins,
2214
- onOutput?, onError }, ctx)` routes `Kind` itself (`host.route`, keeping its `RouteHandle`): a forked worker per
2215
- address over IPC, the link made at the fork, a start message `{ address, start, scripts, lock }` with the app's start
2216
- data and the kind's complete current scripts (`plugins.scripts(kind)`); the 60 s start timer covers fork, lock and
2217
- connect only (Q4). `workers.state` (a JSON watchable per address key), `stop`, `retry`, `step(name)`, `close`;
2218
- `workerMain(fn, { hostPackages, redact, onError })` is the child's side (`fn({ address, start, parent, plugins,
2219
- onClose }, ctx)`, `plugins` a `WorkerPlugins` evaluating the shipped scripts, closers in reverse order). One live
2220
- worker per address (`processLock`: an abstract socket on Linux, a named pipe on Windows, a socket file elsewhere that
2221
- fails closed when stale; a start waits for a draining old holder without polling).
2222
-
2223
- - **Keep-alive** (D9, R3, Q5): the child reports when `host.activity`'s references, jobs and lingering objects and the
2224
- app's `busy` counts flip between all zero and not (local calls do not count; the first state with `ready`, which
2225
- also carries the load report); the server stops a worker idle for `idleMs` (5 min).
2226
- - **Never restarted by itself** (R2): a crash, a `fatal`, a link lost while its child lives (killed after a 5 s grace)
2227
- or a failed start leaves the address failed; its holders see `failed { waiting }` and stay on the path (Q1);
2228
- `retry(address)` or a rollout reaching workers clears it and starts the held ones (Q2). `stop` suspends the address
2229
- while it has holders (R1, Q3).
2230
- - **Errors in public and private** (decision "worker errors in public"): `state` and holders get a fixed message
2231
- (`worker failed to start`, `worker exited (SIGSEGV)`) or the child's redacted `fatal`; the full error and the stderr
2232
- tail go only to `onError` (`worker_failed`). Every app hook of a start (`start`, `principal`, `lock`, the fork) is
2233
- inside that boundary; a throwing `authorize` refuses the hold and is reported `authorize_failed`. `worker_exited` is
2234
- reported only for an exit nobody asked for.
2235
- - **Workers never build** (D11): the server's plugins component builds every plugin; workers evaluate shipped
2236
- complete sets (`createPluginRuntime`, no esbuild); `workers.step(name)` ships a rollout's set to every worker (D12:
2237
- `{ host, report } | { host, stopped: true } | { host, error }` per worker).
2238
-
2239
- ### Channels
2240
-
2241
- WebSocket byte channels with acknowledged windows, separate from object links, wait for a second user after the
2242
- terminals (slice 10 D6); they would be built on top of plugin sockets.
2243
-
2244
- ### Chunked transfers
2245
-
2246
- Large byte transfers are chunked by the owning object: `begin`, `append({ upload, offset, bytes })`, `finish`,
2247
- `read({ id, offset, length })`, about 1 MiB per chunk. The awaited `append` is the backpressure; after a drop the
2248
- writer asks for the stored offset and resumes; unfinished uploads expire (the owner's routine). A helper wraps the
2249
- loop. Chord has no stream type (it would need its own rules for drops, cancellation, relays and restarts).
2250
-
2251
- ---
2252
-
2253
- ## 24. Durable integration and portability
2254
-
2255
- ### Durable
2256
-
2257
- - Durable keeps importing today's Chord's `context`, `delta`, `json`, `output` and `sqlite`; `next/` imports the same
2258
- modules, so `Context`, `Draft` and `JsonValue` are one type. Durable's conversation view, task graph and documents
2259
- are `Watchable`s through Durable's watches (Durable's `WatchHandle` now lives in Chord); Durable adopts and dispatches
2260
- them synchronously inside the storage's commit (S1, W1; with `StoreStorage` that is the store's commit step), so a derive over a Durable view travels with it. This needs Durable to publish a commit when it adopts it (owner, 2026-10-26; a pi change, upstream first; explainer `durable-observers/`): inside `adopt`, its trackers, telemetry events and internal observers (view mounts, task graph, scheduler, submissions) run, and the host `observeCommits` observers are dispatched in one microtask queued before the observers, so they run before every wait the commit resolves and every abort it queues, but after the storage's synchronous step, never inside Chord's batch; host listeners and watch listeners have no order between them (owner, 2026-10-26). Durable's public primitive for adapters is a synchronous observer, `observeConversation`, `observeTaskGraph`, `observeDoc` (its `advance(call, ctx)` gets a `WatchCall` and runs inside `adopt`: record only, no awaits, no Session calls, no throws); `watchXXX` is built on it for app code. Chord's `self.follow(attach)` (slice 6b D9) is a source over it. Otherwise a derive over two Durable views computes between their frames of one commit. With `StoreStorage`, Durable's `adopt` runs inside the host's batch; the store knows nothing of Durable (no special cases) and needs only its step and flush to stay synchronous. Durable's
2261
- state getters (`documentState`, `viewState`, `taskGraph()`) and the `replicatedState` family are removed (W14). Only
2262
- plain data crosses between Durable and v2 objects.
2263
- - **The harness is an object in the core facet** (base code): a `Harness` `local` object with empty params, so host lifetime (it runs for the worker's whole life,
2264
- whether or not anyone holds it) opens Durable paused with `self.open` during the barrier and gets model
2265
- access and execution environments from registry entries, looked up at each use:
2266
-
2267
- ```ts
2268
- const models = self.registry(HarnessModels); // declared dependencies (slice 8 S3): activation waits
2269
- const envs = self.registry(HarnessEnvironments);
2270
- const extensions = self.registry(HarnessExtensions);
2271
- const harness = self.open(async (context) => Harness.open(await StoreStorage.open(store, Harness.name, context), {
2272
- models: () => models.value, // read at use
2273
- env: (target) => envs.value(target.cwd),
2274
- settings: () => currentSettings(),
2275
- registry: registryReader(extensions, context), // Durable's RegistryReader over the composed value (slice 8)
2276
- }, context), (h, _reason, context) => h.close(context));
2277
- ```
2278
-
2279
- Durable's `models` and `settings` accept functions (pi `7ec1f648e`). Durable opens with scheduling paused; base code
2280
- calls `harness.resume()` after `await host.load(...)`; the worker connects to its parent first (W6), so host-lifetime
2281
- stores can reference server types during the barrier; requests arriving during `load` park like any call to a
2282
- loading object (refines R17). A missing tool gives its call an error result the model sees; a missing model makes the generation
2283
- report "model unavailable" and wait (not fail) until a model contribution appears; a task whose definition is missing
2284
- stays blocked (`missing_task`) until the plugin is installed or the task is aborted, as Durable does.
2285
- - **Durable's views from other objects** (slice 8 §5): the harness object contributes its `Native<Harness>` to a
2286
- registry of p3's; another object declares that registry (`self.registry`), wakes on it (`self.retryOn`) and follows
2287
- a view through its value (`self.follow`). A Session close ends Durable's synchronous observers `failed` ("session
2288
- closed"; decision "Slice 8 S1"; app watches still end `ended`), so the follower fails `transient` and follows the
2289
- next Harness once its contribution arrives. `registryReader`'s listener runs inside Chord's batch: it only wakes
2290
- Durable's scheduler (a Chord call there throws `invalid/reentrant`).
2291
- - `HarnessModels` and `HarnessEnvironments` start with one contribution each, from the models and envs plugins'
2292
- objects that own the natives; several providers or environment kinds are their `compose`. After a models reload
2293
- the next request uses the new runtime; a running stream finishes on the old one.
2294
- - **Chord from Durable code (Q6):** tools, hooks and sections get Durable's `ToolExecutionApi` and a `Context`, never a
2295
- Chord `ctx`. p3's core opens the harness with a base context holding the host under a typed key
2296
- (`withContextValue(ChordHostKey, host, …)`); every phase context inherits it. A core helper opens a call scope from
2297
- any Durable context: `chord(async (ctx) => …, context)` = `host.root(fn, context)` (host principal; attribution as
2298
- data; references released when `fn` settles; slice 8 D3). No wrapping of
2299
- tools and no p3 `defineTool`. Clients are never reachable this way (they are not addressable): a tool that needs the
2300
- user goes through an owner's state, e.g. the Questions service (`apps/p2/docs/questions.md`): the model-facing
2301
- `ask_user` tool and any other tool call `Questions.ask`/`wait`, tabs render the open questions and `answer` them.
2302
- Documented with this example.
2303
- - **Code mode** (a plugin) keeps owning its `pi-codemode` sandbox; its tool entry looks up the current sandbox when
2304
- `execute()` starts, so a call pinned by a phase before a reload (e.g. waiting in an approval hook) starts on the new
2305
- sandbox; on `reload` and `close` its `close` detaches the old sandbox, returns at once and disposes of it when its
2306
- scripts finish or after `closeTimeout` (30 s at most, R16, Q7); after a worker stop Durable replays as today.
2307
- - **Telemetry:** `HarnessOptions.telemetry`; submissions and tasks store an optional carrier (section 29).
2308
-
2309
- ### Portability
2310
-
2311
- Adopted in the kernel: host = identity plus incarnation; the loader is an adapter; values independent of the
2312
- transport; durable state only in persisted documents. A Durable Object deployment
2313
- (`apps/p2/docs/research/chord-on-durable-objects.md`) would map a logical host to a DO, compose plugins at build time
2314
- (Workers forbid `eval`), replace the relaying tree with edge routing and use alarms for routines.
2315
-
2316
- > **Decision needed: a Durable Object profile.** Problem: a DO can lose its memory while clients stay connected
2317
- > (hibernation); routines need wake-ups (one alarm per DO); links between DOs are RPC stubs. Hot reload is not needed
2318
- > there; plugin composition is. For later.
2319
-
2320
- ---
2321
-
2322
- ## 25. Apps: ownership and porting
2323
-
2324
- - **Every thing has one owner, the smallest object it belongs to;** ownership nests; rules set at creation are written
2325
- in the creating commit (Durable `createConversation` with `init`).
2326
- - **Core owners are always present;** a plugin owner may be missing (optional dependencies are registries owned by the
2327
- dependent, section 7). Avoid a core god object: each core owner owns only what belongs to it.
2328
- - **Revocation of work in shared stores:** a store that runs work on behalf of a principal stores the grant (or device)
2329
- as data with the work and reconciles from the grant owner's live grants (a routine aborts jobs, withdraws questions,
2330
- drops queued input whose grant no longer exists); no revocation hook. The window between a revocation and the
2331
- routine's run is accepted (R10): a step started in it still runs; there is always some window.
2332
- - **Reading without starting a worker** is plain pub/sub in an ordinary plugin: a host-lifetime object of its worker facet
2333
- records the summary locally and publishes it to the plugin's server object (a method call from a routine on the source); clients read
2334
- the server object, which never starts a worker; it keeps the latest value per session (a document if it must
2335
- survive a server restart) and ignores reports from an older worker incarnation. **The caller's incarnation is
2336
- stamped by Chord (R20):** a call arriving over a link carries the calling host's incarnation from the link handshake
2337
- (`ctx.incarnation`, next to `ctx.principal`, not part of the principal or its key, so object identities do not
2338
- change with restarts); nobody sends it as data and it cannot be forged. On relayed calls it is the **origin** host's
2339
- incarnation (Q13, owner, 2026-10-21): the relay takes it from the link the hold came in on and sends it in
2340
- the upstream `hold` (a client's value is ignored, like its principal); calls inherit their hold's (section 4). Session list, status, children, unread and
2341
- artifact lists follow this.
2342
- - **Porting guideline:** what core enforces on data lives in a format core owns, written by the plugin that creates
2343
- the data; a plugin's private document is read only by that plugin. Example: subagents mark one-shot and
2344
- cwd-following child conversations in a core per-conversation policy document (`readOnly`, `followsSessionCwd`);
2345
- chat and relocation read it; `ReadOnlyConversations` and `SessionCwdFollowers` go away.
2346
- - **p3 is built next to p2,** fully isolated (`apps/p3`, own data directory), without migrating p2 data; plugins are
2347
- derived from the functionality map (`apps/p2/docs/p3-functions/`), not ported one to one.
2348
- - **Session lifecycle:** archive retires nothing (stops the worker, ends guest access, closes forwards); a session
2349
- delete removes the whole session (tagged documents, the worker's databases, files, the catalog entry).
2350
-
2351
- ---
2352
-
2353
- ## 26. Decisions needed
2354
-
2355
- Open, decided with the slice named or a concrete case (numbers kept stable; everything else is decided and folded into
2356
- this document):
2357
-
2358
- | # | Topic | Section | When |
2359
- | --- | --- | --- | --- |
2360
- | 11 | where a flow lives | 20 | when login is ported |
2361
- | 14 | project plugins | 21 | own pass over `plugin-loading.md` |
2362
- | 16 | a Durable Object profile | 24 | when a DO target becomes concrete |
2363
- | 24 | a per-type drain override: a host option or fixed (no install watchdog: `reload` takes the app's context, decision "Slice 7b's open points" (4); the routine handover uses `closeTimeout`; a failing job `finish` backs off 1-60 s and blocks after five failures, decided) | 3 | if a real case needs it |
2364
- | 28 | Astra's circuit breaker (a hard transport-buffer cap plus a stall deadline); the heartbeat is built, the cap was never decided | 3 | if a real case needs it |
2365
- | 29 | round-3 cut C11 (`ctx.trace`); C3 and C4 are decided (§14, §15) | 8 | slice 9 |
2366
-
2367
- Apps (p3), from the functionality map, decided per domain when p3 is designed:
2368
-
2369
- | # | Topic | Problem and options |
2370
- | --- | --- | --- |
2371
- | 17 | session files | one owner `SessionFiles {session}` on the server for uploads, sent-file snapshots and artifact versions (caps per kind, index readable without a worker, copy on clone/fork, delete with the session); proposed, sub-points: one preview limit, fork's artifact list, copying attachments into remote environments |
2372
- | 18 | session delete | per-session objects plus `SessionTag` plus a session directory, or owner hooks through a registry; search index per session or global plus a hook |
2373
- | 20 | connection pools | SSH connections to one environment exist four times: one owner with a pool, or per-use connections |
2374
- | 21 | config files with a single writer | settings, models and auth are watched by every process and written by two: one owner on the server, others follow its state |
2375
- | 22 | file formats as versioned interfaces | `envs.json`, downloads, uploads have no version: version them like documents, or keep each internal to one owner |
2376
- | 23 | the terminal host process | a detached process with its own code: part of the revision (reloaded or restarted with it) or deliberately outside |
2377
-
2378
- ---
2379
-
2380
- ## 27. Versions and adapters
2381
-
2382
- | Surface | Version | On change |
2383
- | --- | --- | --- |
2384
- | object type | `version` plus contract fingerprint | every change bumps; forward evolution and `checkAccepts` (Q10); otherwise `contract_mismatch` |
2385
- | registry | `version` | `accepts` adapter on contributions |
2386
- | document | `version` plus schema fingerprint | pure `migrate`, on access; a schema change without a bump fails the object `broken` |
2387
- | job | `version` | `accepts` maps older args and results forwards (`finish`, `running`); the state document's own `migrate`; `blocked` without an adapter or for a newer version |
2388
- | native | none | the object restarts on reload |
2389
- | Durable tasks and documents | `version` | Durable's `migrate` |
2390
- | link protocol | protocol version | refused; hosts update together |
2391
- | UI components, Chord and app APIs | none yet | exposed as they are; versioned with an SDK later |
2392
-
2393
- **Contract evolution in code (Q10; implemented in `packages/chord/src/next/contracts/`, see its README):**
2394
-
2395
- ```ts
2396
- export const NotesV1 = remote("notes", { version: 1, params, variants: {
2397
- editor: { state: { notes: arr(NoteV1) }, methods: { add: method(NoteV1, Id) } },
2398
- } });
2399
- export const NotesV2 = evolve(NotesV1, (e) => e.state("editor", "notes", arr(NoteV2)).args("add", NoteV2));
2400
-
2401
- const accepted = checkAccepts(NotesV2, {
2402
- 1: { state: { editor: { notes: (current) => current.map(toV1) } }, methods: { add: { args: (old) => toV2(old) } } },
2403
- });
2404
- ```
2405
-
2406
- - A history starts with a base written in full with an explicit version (`remote()` / `local()`; `local` has flat
2407
- `members` and no variants). `evolve(prev, (e) => …)` always continues it with structured edits: `state`,
2408
- `addState`, `removeState`, `args`, `result`, `method(name, args, result)`, `addMethod`, `removeMethod` (local: no
2409
- variant argument), and for a local contract's keyed members `keyed`, `addKeyed`, `removeKeyed` (slice 7b; owner,
2410
- 2026-10-26: keyed members' versions are mapped per key). Every version is materialized and fingerprinted at declaration, so an old plugin's own copy of
2411
- v1 computes the same fingerprint; no build step, no generated files, no hand-copied fingerprints.
2412
- - **A new history base** (a params change or a change of the variant set) is a new `remote()`/`local()` with an
2413
- explicit version and no accepts for older versions: old plugins get `contract_mismatch` and must update.
2414
- - **Mappings live with the provider,** never in the contract: the pure `checkAccepts(contract, accepts)` (called by
2415
- the objects layer) requires, at type level and again at runtime, a mapping for every member that exists in the old
2416
- version and changed or was removed since: changed state `(currentMember) => oldMember`, removed state `(current
2417
- variant state) => oldMember` or `"refuse"`, `args: (old) => current`, `result: (current) => old`, removed methods
2418
- `{ call }` or `"refuse"`, changed keyed members `(current document) => old document` or `"refuse"` (mapped per key
2419
- for an older local consumer), removed keyed members `"refuse"`; added members need nothing. No-op edits need identity mappings. Untyped JavaScript
2420
- providers fail at declaration naming the member; unknown keys and wrong shapes are rejected.
2421
- - **The fingerprint** is a hash (`hash64`, portable, not a security boundary) of a schema-aware, data-only normal form
2422
- (`NORMAL_FORM_VERSION`, tied to the protocol): annotations dropped only on schema nodes, `required`/`enum` sorted,
2423
- union and intersection order kept (it is meaning: defaults), a whitelist of JSON Schema keywords, executable features
2424
- rejected; bytes are a `{ type: "bytes" }` data marker. Schemas are deep-copied into a private history (never frozen; immutable by convention).
2425
- - **Schema helpers:** `str num int bool nul lit oneOf union obj arr map opt bytes unknown` and `type Static`.
2426
- - Chord wraps state mappings as a derive and diffs per object and version (section 22); members an old consumer does not know do
2427
- not appear.
2428
- ---
2429
-
2430
- ## 28. Building: slices
2431
-
2432
- Chord v2 is built in vertical slices; the plan, the feature map (every feature of this document assigned to the slice
2433
- that builds it) and the carry-over of deferred obligations are in `slices.md`. Slice specs (`slice-N.md`) stay as the
2434
- history of how each slice was specified; this document states the current rules. The first layered build (kernel steps
2435
- 1-6) was deleted on 2026-10-22 and survives only in git history. Done in pi: `pi-telemetry` (propagation, links,
2436
- metrics, the store interface, the renderer), `chord/context` (`Context.telemetry`), pi-ai and Durable telemetry,
2437
- `chord/telemetry-sqlite` (section 29), Chord's shared `Watch`/`NativeWatch`/`PendingOps`, Delta's `appendText`.
2438
-
2439
- **Rules for every slice** (owner, 2026-10-22): the code follows the root `AGENTS.md` section "Chord v2 Code Style";
2440
- one test file per source file, one `describe` per mechanism, the spec's test list case by case; cost guards through the
2441
- in-memory telemetry adapter (section 30); GC tests for every cache and binding; one or more runnable examples
2442
- (`packages/chord/test/next/examples/NN-topic.ts`); hot-path slices add a light benchmark script
2443
- (`test/next/bench/`, by hand) with results in `benchmarks.md`; `npm run check` and the slice's tests before reporting.
2444
- Caches are `WeakMap`s keyed by their owner; no module-level strong caches; no hot-path work no decision asked for. The
2445
- function doing counted work counts it through its context; call sites never count for others; plain totals without
2446
- site labels.
2447
-
2448
- **Testing the core:** every slice spec contains an explicit test list, one group per mechanism with its edge cases,
2449
- tested individually and exhaustively: activation and parked dependencies (the dependency model: unbound requests, waits without timers, wakes on every
2450
- change, retry passing on, a dependency failing while live, cycles, the start barrier's first outcomes), revocation over running jobs (R11), compatibility (R6), params
2451
- and arguments for every caller (R7), migration results and old calls on migrated documents (R8, R15), flow control
2452
- (the window per origin, folding, relays forwarding and returning acks), the incarnation fence (R20), the harness start
2453
- after the barrier (R17), native restart patterns (R16), and W1's publication list (a throwing derive, a chain A→B→C
2454
- where B throws, two owners alternating with a derive over both, reentrancy, a watch started after 150 frames, stop
2455
- during a running call, a retire with a derive over it, a reload during a routine call, GC counts of retained
2456
- revisions).
2457
-
2458
- ---
2459
-
2460
- ## 29. Telemetry
2461
-
2462
- Chord reports traces, events and metrics through `@earendil-works/pi-telemetry`; one adapter per host
2463
- (`createHost({ telemetry })`, NOOP by default) decides sampling, buffering, export and filtering.
2464
-
2465
- - **Types:** the adapter is a `TelemetryContext` (`startSpan` plus optional readonly `metrics` and `propagation`
2466
- capabilities); only hosts hold it, to start roots. `Context.telemetry` is always a `TelemetrySpan` (the NOOP span by
2467
- default); every span carries its adapter's `metrics` and `propagation`, so code with a context can record metrics
2468
- and inject carriers. `withTelemetry(span, context)`, `traceIn(options, fn, context)` (context last; pi change with S1); `value()` and keys stay.
2469
- `Ctx` extends `Context`, so `ctx.telemetry` is the current span; app values such as the principal stay out of
2470
- Durable's context. `ctx.trace(name, attributes, fn)` creates a child span and gives `fn` a child `ctx`.
2471
- - **Adapters trust typed inputs:** no validation of malformed caller values and no try/catch around recording; only
2472
- carriers from another process are checked (keys present, strings), else the root. Callers never protect themselves
2473
- against broken adapters.
2474
- - **Across links:** `call` and `hold` carry the caller's carrier as a bounded header field (section 22); the provider
2475
- extracts it and runs the method under it; relays add a `chord.relay` span.
2476
-
2477
- ```
2478
- chord.call Notes.add [tab A]
2479
- └─ chord.relay [server]
2480
- └─ chord.method Notes.add [session:S1] principal=guest
2481
- · event chord.commit docs=2 ops=5
2482
- ```
2483
-
2484
- - **Shared work** (one activation for several getters, a worker start) is its own root span linked to its first
2485
- trigger; each waiting span links to it. Routine runs, job runs, eviction, backoff retries and background closes are
2486
- root spans linked to their trigger where one exists.
2487
- - **Tiers:** spans for calls, methods, relays, holds, activations, opens, closes, loads, revocations, resolves, routine
2488
- runs and job runs; events for commits inside methods, retries and parking; metrics for state messages, WebSocket
2489
- bytes, commit durations, in-flight calls, active holds, open links, park durations and backpressure waits. IDs are
2490
- attributes of spans, never of metrics.
2491
- - **Nothing is measured or walked for telemetry:** only sizes the code already has. Errors carry a fixed category and
2492
- a message truncated to 500 characters; cancelling is not an error.
2493
- - **A typed telemetry schema** ships with Chord, as pi-ai (`AI_TELEMETRY_SCHEMA`) and Durable
2494
- (`DURABLE_TELEMETRY_SCHEMA`) have; call sites that only have a context use the generic `addEvent`.
2495
- - **Storage and reading:** `@earendil-works/chord/telemetry-sqlite` over `chord/sqlite` (Node and Cloudflare): one
2496
- row per settled span (events and links inline), metrics aggregated per series per 10 s, a 1 s batched flush with
2497
- retention (7 days), a bounded queue (dropped and counted). The shared read interface `TelemetryStore` (Jaeger
2498
- style): `findTraces` (name, attributes, errors, time window, limit, cursor) returns complete traces, `getTrace`,
2499
- `findMetrics`. Spans carry global ids and a trace id; links carry trace and span id. One renderer
2500
- (`pi-telemetry/render`) prints links and never follows them. A web trace viewer in the playground reads the store.
2501
- - **Durable** (done): submit and phase spans, stored carriers on submissions and tasks (`TaskOptions.trace`, creation
2502
- links), events after commit, report events; pi-ai emits `pi.ai.request`/`pi.ai.poll` from one observer in
2503
- `lazyStream`. Persisted Chord jobs store their start carrier.
2504
-
2505
- ## 30. Cost model
2506
-
2507
- As little compute and memory as possible while staying correct; Delta was built for this (its own primitives are
2508
- practically free: `diffRevisions` on shared subtrees 0.018 ms, `applyImmutable` per small change 0.004 ms). Measured
2509
- before/after per hop: `apps/p2/docs/p3-reviews/v2-cost-model.md`.
2510
-
2511
- | Hop | Work |
2512
- | --- | --- |
2513
- | commit | Delta's `prepare` (copies and checks only placed values), adopt by pointer swap; storage writes the delta |
2514
- | reads in a transaction | the draft overlay, no copy; unchanged = no write |
2515
- | subscribers on the same host | the same value and ops by reference |
2516
- | derives | compute plus `diffRevisions`; unchanged parts stay the same objects (`mapShared`, cookbook) |
2517
- | send | one encode per touched hold member per commit at its origin (the member's Delta encoder); while the window is full, per op one path key and one map lookup (leaf index), and one encode per waiting member per freed slot |
2518
- | relay, per message | decode the envelope, swap the origin (one shallow copy), encode the envelope; parts copied once into the outgoing buffer, never parsed; per `bound`/`state` one FIFO entry; two bytes of origin per message upstream |
2519
- | relay, per hold | the address's params checked once (route admission, `authorize`) |
2520
- | receive | the compiled `MESSAGE` check on untrusted links; arguments validated once at the provider (compiled closed schema), params checked; one `ack` per `bound`/`state` message |
2521
- | heartbeat | one timestamp write per received message; one timer per host |
2522
- | apply | `applyImmutable`, structure shared |
2523
- | new hold | the value encoded once (unavoidable) |
2524
- | memory | one authoritative value per document per host; replicas and derived values share structure; one cached value per adapted member, object instance and version (while a reference of the version holds it) |
2525
-
2526
- **Cost guards:** Chord reports full-value walks, deep copies, encodes, schema validations and materializations as
2527
- ordinary telemetry metrics, always on (no test mode; with the NOOP adapter they cost an empty call where such work
2528
- happens). Tests use the in-memory adapter and assert them per hop (e.g. one appended note to a 500 KB document with
2529
- 10 viewers: no walks, no copies, one encode per hold part at its origin and none at relays, no validations); a `vitest bench` suite measures the hops.
2530
-
2531
- ---
2532
-
2533
- ## 31. Rejected
2534
-
2535
- `replicatedState` and its source family as public API; a separate IndexedDB backend; generic JSON rows and
2536
- store-maintained index entries; last-write-per-row compaction; recording raw SQL statements or SQLite changesets;
2537
- plugins' own databases holding source data; rollback after losing the driver role; JSON-field operands in bulk
2538
- updates (until needed); a lazy-lifetime flag; a `lifetime` option; derive `previous`. Drain-based handover; version fences without transactions; object restart for state changes; Durable's Session as the
2539
- object store; volatile documents; per-group lines; generic call or request ids; optimistic transactions; an outbox for
2540
- transient delivery errors; revoking proxies on `.value`; resources replaced in place (`replace`, `deps`, stale
2541
- handles); registries created at runtime and entries resolved through mutable indirection (contributions that change
2542
- with their contributor, readable contributions and readers looking up the current value at use are fine, R25); generic
2543
- registry keys with a `conflict` flag;
2544
- `restart_required`; detached references counting toward presence; contracts taken from the running app; ceremony
2545
- (`native/` directories, `defineNative`, lints); weakening type checking; "magic" input-field matching for delete; a
2546
- factory trial; a migrate dry run; principal field patterns and re-stamping for revocation; `storeKey`; a consumer contract check during staging; reload votes; `defaultProjectTrust: "always"`; loader variants A and B; a topology layer above the host API; a stream type in
2547
- Chord; callbacks as method arguments; `opaque` members; numeric middleware priorities; host addresses as data naming an
2548
- input field; host-name strings in app code; host values (start data and platform bindings are core objects);
2549
- consumer-side linger; registry composition as a staging check; a JSONL document storage; `tx.get` for documents; validating state and documents on commits or reads (migration results are validated once, R8); copying values on same-host calls; op-rewriting projections and a
2550
- view algebra; keeping natives across reloads by name; Chord ending the process on a storage failure; an `optional`
2551
- flag on references; cross-relay reset coordination; count limits that refuse calls or holds; relays acking per hop, relay resets
2552
- (`reset { hold }`, `reset { holds }`), relay recovery and id renumbering at relays (replaced by flow control per
2553
- origin); a byte window, credit messages, snapshot admission and debt; `reset` from a consumer; a round-robin of
2554
- relayed calls at the relay; `state: false` on references (C8); `inVariant`/`expectVariant` (C15); per-call deadlines.