@statewalker/cellb 0.0.0-stage → 0.1.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 (365) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +323 -2
  3. package/dist/adapters/files-backup.d.ts +16 -0
  4. package/dist/adapters/files-backup.js +32 -0
  5. package/dist/adapters/files-backup.js.map +1 -0
  6. package/dist/adapters/files-changelog.d.ts +33 -0
  7. package/dist/adapters/files-changelog.js +96 -0
  8. package/dist/adapters/files-changelog.js.map +1 -0
  9. package/dist/adapters/files-ltx.d.ts +35 -0
  10. package/dist/adapters/files-ltx.js +9 -0
  11. package/dist/adapters/files-ltx.js.map +1 -0
  12. package/dist/adapters/ltx-vfs.d.ts +21 -0
  13. package/dist/adapters/ltx-vfs.js +286 -0
  14. package/dist/adapters/ltx-vfs.js.map +1 -0
  15. package/dist/adapters/node-sqlite.d.ts +45 -0
  16. package/dist/adapters/node-sqlite.js +254 -0
  17. package/dist/adapters/node-sqlite.js.map +1 -0
  18. package/dist/adapters/wasm-page-hook.d.ts +26 -0
  19. package/dist/adapters/wasm-page-hook.js +55 -0
  20. package/dist/adapters/wasm-page-hook.js.map +1 -0
  21. package/dist/adapters/wasm-session.d.ts +11 -0
  22. package/dist/adapters/wasm-session.js +76 -0
  23. package/dist/adapters/wasm-session.js.map +1 -0
  24. package/dist/adapters/wasm-sqlite.d.ts +89 -0
  25. package/dist/adapters/wasm-sqlite.js +258 -0
  26. package/dist/adapters/wasm-sqlite.js.map +1 -0
  27. package/dist/bindings/assets.d.ts +26 -0
  28. package/dist/bindings/assets.js +260 -0
  29. package/dist/bindings/assets.js.map +1 -0
  30. package/dist/bindings/cache.d.ts +16 -0
  31. package/dist/bindings/cache.js +34 -0
  32. package/dist/bindings/cache.js.map +1 -0
  33. package/dist/bindings/celld-kv.d.ts +26 -0
  34. package/dist/bindings/celld-kv.js +81 -0
  35. package/dist/bindings/celld-kv.js.map +1 -0
  36. package/dist/bindings/celld-queues.d.ts +56 -0
  37. package/dist/bindings/celld-queues.js +223 -0
  38. package/dist/bindings/celld-queues.js.map +1 -0
  39. package/dist/bindings/celld-workflows.d.ts +22 -0
  40. package/dist/bindings/celld-workflows.js +54 -0
  41. package/dist/bindings/celld-workflows.js.map +1 -0
  42. package/dist/bindings/cron.d.ts +27 -0
  43. package/dist/bindings/cron.js +232 -0
  44. package/dist/bindings/cron.js.map +1 -0
  45. package/dist/bindings/d1-migrations.d.ts +22 -0
  46. package/dist/bindings/d1-migrations.js +32 -0
  47. package/dist/bindings/d1-migrations.js.map +1 -0
  48. package/dist/bindings/html-rewriter.d.ts +8 -0
  49. package/dist/bindings/html-rewriter.js +75 -0
  50. package/dist/bindings/html-rewriter.js.map +1 -0
  51. package/dist/bindings/r2-celld.d.ts +3 -0
  52. package/dist/bindings/r2-celld.js +113 -0
  53. package/dist/bindings/r2-celld.js.map +1 -0
  54. package/dist/bindings/r2.d.ts +236 -0
  55. package/dist/bindings/r2.js +419 -0
  56. package/dist/bindings/r2.js.map +1 -0
  57. package/dist/bindings/worker-loader.d.ts +83 -0
  58. package/dist/bindings/worker-loader.js +183 -0
  59. package/dist/bindings/worker-loader.js.map +1 -0
  60. package/dist/bindings/workers-ai.d.ts +39 -0
  61. package/dist/bindings/workers-ai.js +175 -0
  62. package/dist/bindings/workers-ai.js.map +1 -0
  63. package/dist/browser.d.ts +7 -0
  64. package/dist/browser.js +8 -0
  65. package/dist/browser.js.map +1 -0
  66. package/dist/bucket/celld-cells.d.ts +86 -0
  67. package/dist/bucket/celld-cells.js +273 -0
  68. package/dist/bucket/celld-cells.js.map +1 -0
  69. package/dist/bucket/celld-format.d.ts +10 -0
  70. package/dist/bucket/celld-format.js +27 -0
  71. package/dist/bucket/celld-format.js.map +1 -0
  72. package/dist/bucket/idb-object-store.d.ts +9 -0
  73. package/dist/bucket/idb-object-store.js +73 -0
  74. package/dist/bucket/idb-object-store.js.map +1 -0
  75. package/dist/bucket/ltx-log.d.ts +34 -0
  76. package/dist/bucket/ltx-log.js +289 -0
  77. package/dist/bucket/ltx-log.js.map +1 -0
  78. package/dist/bucket/object-store.d.ts +51 -0
  79. package/dist/bucket/object-store.js +114 -0
  80. package/dist/bucket/object-store.js.map +1 -0
  81. package/dist/bucket/s3-object-store.d.ts +25 -0
  82. package/dist/bucket/s3-object-store.js +151 -0
  83. package/dist/bucket/s3-object-store.js.map +1 -0
  84. package/dist/bucket/sqlite-object-store.d.ts +10 -0
  85. package/dist/bucket/sqlite-object-store.js +107 -0
  86. package/dist/bucket/sqlite-object-store.js.map +1 -0
  87. package/dist/core/alarms.d.ts +27 -0
  88. package/dist/core/alarms.js +88 -0
  89. package/dist/core/alarms.js.map +1 -0
  90. package/dist/core/async-context.d.ts +34 -0
  91. package/dist/core/async-context.js +50 -0
  92. package/dist/core/async-context.js.map +1 -0
  93. package/dist/core/celld-schema.d.ts +14 -0
  94. package/dist/core/celld-schema.js +34 -0
  95. package/dist/core/celld-schema.js.map +1 -0
  96. package/dist/core/durable-object.d.ts +28 -0
  97. package/dist/core/durable-object.js +31 -0
  98. package/dist/core/durable-object.js.map +1 -0
  99. package/dist/core/gates.d.ts +33 -0
  100. package/dist/core/gates.js +89 -0
  101. package/dist/core/gates.js.map +1 -0
  102. package/dist/core/handles.d.ts +90 -0
  103. package/dist/core/handles.js +224 -0
  104. package/dist/core/handles.js.map +1 -0
  105. package/dist/core/id.d.ts +19 -0
  106. package/dist/core/id.js +64 -0
  107. package/dist/core/id.js.map +1 -0
  108. package/dist/core/namespace.d.ts +38 -0
  109. package/dist/core/namespace.js +141 -0
  110. package/dist/core/namespace.js.map +1 -0
  111. package/dist/core/object-host.d.ts +91 -0
  112. package/dist/core/object-host.js +616 -0
  113. package/dist/core/object-host.js.map +1 -0
  114. package/dist/core/request-body.d.ts +9 -0
  115. package/dist/core/request-body.js +55 -0
  116. package/dist/core/request-body.js.map +1 -0
  117. package/dist/core/runtime.d.ts +121 -0
  118. package/dist/core/runtime.js +366 -0
  119. package/dist/core/runtime.js.map +1 -0
  120. package/dist/core/shard.d.ts +7 -0
  121. package/dist/core/shard.js +10 -0
  122. package/dist/core/shard.js.map +1 -0
  123. package/dist/core/sql-split.d.ts +15 -0
  124. package/dist/core/sql-split.js +101 -0
  125. package/dist/core/sql-split.js.map +1 -0
  126. package/dist/core/sql-storage.d.ts +53 -0
  127. package/dist/core/sql-storage.js +407 -0
  128. package/dist/core/sql-storage.js.map +1 -0
  129. package/dist/core/state.d.ts +44 -0
  130. package/dist/core/state.js +93 -0
  131. package/dist/core/state.js.map +1 -0
  132. package/dist/core/storage.d.ts +103 -0
  133. package/dist/core/storage.js +351 -0
  134. package/dist/core/storage.js.map +1 -0
  135. package/dist/core/worker-rejections.d.ts +21 -0
  136. package/dist/core/worker-rejections.js +55 -0
  137. package/dist/core/worker-rejections.js.map +1 -0
  138. package/dist/index.d.ts +22 -0
  139. package/dist/index.js +23 -0
  140. package/dist/index.js.map +1 -0
  141. package/dist/isolate/browser.d.ts +16 -0
  142. package/dist/isolate/browser.js +37 -0
  143. package/dist/isolate/browser.js.map +1 -0
  144. package/dist/isolate/host.d.ts +24 -0
  145. package/dist/isolate/host.js +74 -0
  146. package/dist/isolate/host.js.map +1 -0
  147. package/dist/isolate/isolate-worker.d.ts +1 -0
  148. package/dist/isolate/isolate-worker.js +53 -0
  149. package/dist/isolate/isolate-worker.js.map +1 -0
  150. package/dist/isolate/isolate.d.ts +10 -0
  151. package/dist/isolate/isolate.js +169 -0
  152. package/dist/isolate/isolate.js.map +1 -0
  153. package/dist/isolate/node-entry.d.ts +1 -0
  154. package/dist/isolate/node-entry.js +12 -0
  155. package/dist/isolate/node-entry.js.map +1 -0
  156. package/dist/isolate/protocol.d.ts +66 -0
  157. package/dist/isolate/protocol.js +205 -0
  158. package/dist/isolate/protocol.js.map +1 -0
  159. package/dist/ltx/crc64.d.ts +6 -0
  160. package/dist/ltx/crc64.js +46 -0
  161. package/dist/ltx/crc64.js.map +1 -0
  162. package/dist/ltx/ltx-page-server.d.ts +65 -0
  163. package/dist/ltx/ltx-page-server.js +309 -0
  164. package/dist/ltx/ltx-page-server.js.map +1 -0
  165. package/dist/ltx/ltx-pages.d.ts +81 -0
  166. package/dist/ltx/ltx-pages.js +315 -0
  167. package/dist/ltx/ltx-pages.js.map +1 -0
  168. package/dist/ltx/ltx-store-worker.d.ts +1 -0
  169. package/dist/ltx/ltx-store-worker.js +38 -0
  170. package/dist/ltx/ltx-store-worker.js.map +1 -0
  171. package/dist/ltx/ltx.d.ts +45 -0
  172. package/dist/ltx/ltx.js +203 -0
  173. package/dist/ltx/ltx.js.map +1 -0
  174. package/dist/ltx/lz4.d.ts +9 -0
  175. package/dist/ltx/lz4.js +156 -0
  176. package/dist/ltx/lz4.js.map +1 -0
  177. package/dist/ltx/opfs-sync-files.d.ts +23 -0
  178. package/dist/ltx/opfs-sync-files.js +191 -0
  179. package/dist/ltx/opfs-sync-files.js.map +1 -0
  180. package/dist/ltx/xxh32.d.ts +1 -0
  181. package/dist/ltx/xxh32.js +43 -0
  182. package/dist/ltx/xxh32.js.map +1 -0
  183. package/dist/miniflare-compat/blob-service.d.ts +13 -0
  184. package/dist/miniflare-compat/blob-service.js +66 -0
  185. package/dist/miniflare-compat/blob-service.js.map +1 -0
  186. package/dist/miniflare-compat/kv-binding.d.ts +44 -0
  187. package/dist/miniflare-compat/kv-binding.js +99 -0
  188. package/dist/miniflare-compat/kv-binding.js.map +1 -0
  189. package/dist/miniflare-compat/shims/assert.d.ts +15 -0
  190. package/dist/miniflare-compat/shims/assert.js +24 -0
  191. package/dist/miniflare-compat/shims/assert.js.map +1 -0
  192. package/dist/miniflare-compat/shims/workerd-cloudflare.d.ts +7 -0
  193. package/dist/miniflare-compat/shims/workerd-cloudflare.js +6 -0
  194. package/dist/miniflare-compat/shims/workerd-cloudflare.js.map +1 -0
  195. package/dist/miniflare-compat/shims/workerd-globals.d.ts +1 -0
  196. package/dist/miniflare-compat/shims/workerd-globals.js +30 -0
  197. package/dist/miniflare-compat/shims/workerd-globals.js.map +1 -0
  198. package/dist/miniflare-compat/shims/workerd-internal.d.ts +20 -0
  199. package/dist/miniflare-compat/shims/workerd-internal.js +23 -0
  200. package/dist/miniflare-compat/shims/workerd-internal.js.map +1 -0
  201. package/dist/miniflare-compat/shims/workerd-performance.d.ts +4 -0
  202. package/dist/miniflare-compat/shims/workerd-performance.js +17 -0
  203. package/dist/miniflare-compat/shims/workerd-performance.js.map +1 -0
  204. package/dist/miniflare-compat/simulator-fetcher.d.ts +9 -0
  205. package/dist/miniflare-compat/simulator-fetcher.js +14 -0
  206. package/dist/miniflare-compat/simulator-fetcher.js.map +1 -0
  207. package/dist/miniflare-compat/vendored.d.ts +15 -0
  208. package/dist/miniflare-compat/vendored.js +27 -0
  209. package/dist/miniflare-compat/vendored.js.map +1 -0
  210. package/dist/node-compat/async_hooks.d.ts +22 -0
  211. package/dist/node-compat/async_hooks.js +176 -0
  212. package/dist/node-compat/async_hooks.js.map +1 -0
  213. package/dist/node-compat/browser-registry.d.ts +3 -0
  214. package/dist/node-compat/browser-registry.js +39 -0
  215. package/dist/node-compat/browser-registry.js.map +1 -0
  216. package/dist/node-compat/crypto.d.ts +60 -0
  217. package/dist/node-compat/crypto.js +143 -0
  218. package/dist/node-compat/crypto.js.map +1 -0
  219. package/dist/node-compat/diagnostics_channel.d.ts +27 -0
  220. package/dist/node-compat/diagnostics_channel.js +46 -0
  221. package/dist/node-compat/diagnostics_channel.js.map +1 -0
  222. package/dist/node-compat/fs.d.ts +35 -0
  223. package/dist/node-compat/fs.js +40 -0
  224. package/dist/node-compat/fs.js.map +1 -0
  225. package/dist/node-compat/globals.d.ts +3 -0
  226. package/dist/node-compat/globals.js +4 -0
  227. package/dist/node-compat/globals.js.map +1 -0
  228. package/dist/node-compat/install.d.ts +5 -0
  229. package/dist/node-compat/install.js +12 -0
  230. package/dist/node-compat/install.js.map +1 -0
  231. package/dist/node-compat/module.d.ts +12 -0
  232. package/dist/node-compat/module.js +36 -0
  233. package/dist/node-compat/module.js.map +1 -0
  234. package/dist/node-compat/modules.d.ts +8 -0
  235. package/dist/node-compat/modules.js +23 -0
  236. package/dist/node-compat/modules.js.map +1 -0
  237. package/dist/node-compat/os.d.ts +36 -0
  238. package/dist/node-compat/os.js +36 -0
  239. package/dist/node-compat/os.js.map +1 -0
  240. package/dist/node-compat/process.d.ts +14 -0
  241. package/dist/node-compat/process.js +16 -0
  242. package/dist/node-compat/process.js.map +1 -0
  243. package/dist/node-compat/shims.d.ts +4 -0
  244. package/dist/node.d.ts +5 -0
  245. package/dist/node.js +6 -0
  246. package/dist/node.js.map +1 -0
  247. package/dist/peer/celld-peer.d.ts +53 -0
  248. package/dist/peer/celld-peer.js +555 -0
  249. package/dist/peer/celld-peer.js.map +1 -0
  250. package/dist/ports.d.ts +183 -0
  251. package/dist/ports.js +10 -0
  252. package/dist/ports.js.map +1 -0
  253. package/dist/project/browser-bundle.d.ts +17 -0
  254. package/dist/project/browser-bundle.js +125 -0
  255. package/dist/project/browser-bundle.js.map +1 -0
  256. package/dist/project/browser-cookies.d.ts +12 -0
  257. package/dist/project/browser-cookies.js +90 -0
  258. package/dist/project/browser-cookies.js.map +1 -0
  259. package/dist/project/browser-host.d.ts +173 -0
  260. package/dist/project/browser-host.js +200 -0
  261. package/dist/project/browser-host.js.map +1 -0
  262. package/dist/project/browser-modules.d.ts +17 -0
  263. package/dist/project/browser-modules.js +89 -0
  264. package/dist/project/browser-modules.js.map +1 -0
  265. package/dist/project/browser-shards.d.ts +62 -0
  266. package/dist/project/browser-shards.js +210 -0
  267. package/dist/project/browser-shards.js.map +1 -0
  268. package/dist/project/browser-tabs.d.ts +103 -0
  269. package/dist/project/browser-tabs.js +418 -0
  270. package/dist/project/browser-tabs.js.map +1 -0
  271. package/dist/project/cloudflare-email.d.ts +8 -0
  272. package/dist/project/cloudflare-email.js +11 -0
  273. package/dist/project/cloudflare-email.js.map +1 -0
  274. package/dist/project/cloudflare-workers.d.ts +12 -0
  275. package/dist/project/cloudflare-workers.js +16 -0
  276. package/dist/project/cloudflare-workers.js.map +1 -0
  277. package/dist/project/host-modules.d.ts +4 -0
  278. package/dist/project/host-modules.js +40 -0
  279. package/dist/project/host-modules.js.map +1 -0
  280. package/dist/project/jsonc.d.ts +2 -0
  281. package/dist/project/jsonc.js +27 -0
  282. package/dist/project/jsonc.js.map +1 -0
  283. package/dist/project/lower-await.d.ts +2 -0
  284. package/dist/project/lower-await.js +151 -0
  285. package/dist/project/lower-await.js.map +1 -0
  286. package/dist/project/node-project.d.ts +38 -0
  287. package/dist/project/node-project.js +373 -0
  288. package/dist/project/node-project.js.map +1 -0
  289. package/dist/project/own-module.d.ts +6 -0
  290. package/dist/project/own-module.js +13 -0
  291. package/dist/project/own-module.js.map +1 -0
  292. package/dist/project/scheduler.d.ts +2 -0
  293. package/dist/project/scheduler.js +3 -0
  294. package/dist/project/scheduler.js.map +1 -0
  295. package/dist/project/site.d.ts +74 -0
  296. package/dist/project/site.js +206 -0
  297. package/dist/project/site.js.map +1 -0
  298. package/dist/project/virtual-modules.d.ts +3 -0
  299. package/dist/project/worker-scope.d.ts +27 -0
  300. package/dist/project/worker-scope.js +46 -0
  301. package/dist/project/worker-scope.js.map +1 -0
  302. package/dist/project/workerd-message-channel.d.ts +13 -0
  303. package/dist/project/workerd-message-channel.js +137 -0
  304. package/dist/project/workerd-message-channel.js.map +1 -0
  305. package/dist/project/workers-global-names.d.ts +6 -0
  306. package/dist/project/workers-global-names.js +15 -0
  307. package/dist/project/workers-global-names.js.map +1 -0
  308. package/dist/project/workers-globals-module.d.ts +8 -0
  309. package/dist/project/workers-globals-module.js +9 -0
  310. package/dist/project/workers-globals-module.js.map +1 -0
  311. package/dist/project/workers-globals.d.ts +9 -0
  312. package/dist/project/workers-globals.js +19 -0
  313. package/dist/project/workers-globals.js.map +1 -0
  314. package/dist/project/wrangler.d.ts +116 -0
  315. package/dist/project/wrangler.js +342 -0
  316. package/dist/project/wrangler.js.map +1 -0
  317. package/dist/router/cell-router.d.ts +72 -0
  318. package/dist/router/cell-router.js +247 -0
  319. package/dist/router/cell-router.js.map +1 -0
  320. package/dist/router/shard-worker.d.ts +44 -0
  321. package/dist/router/shard-worker.js +163 -0
  322. package/dist/router/shard-worker.js.map +1 -0
  323. package/dist/transport/cells-http.d.ts +25 -0
  324. package/dist/transport/cells-http.js +141 -0
  325. package/dist/transport/cells-http.js.map +1 -0
  326. package/dist/transport/cells-link.d.ts +27 -0
  327. package/dist/transport/cells-link.js +71 -0
  328. package/dist/transport/cells-link.js.map +1 -0
  329. package/dist/transport/port.d.ts +26 -0
  330. package/dist/transport/port.js +100 -0
  331. package/dist/transport/port.js.map +1 -0
  332. package/dist/v8/codec.d.ts +6 -0
  333. package/dist/v8/codec.js +9 -0
  334. package/dist/v8/codec.js.map +1 -0
  335. package/dist/v8/serialize.d.ts +10 -0
  336. package/dist/v8/serialize.js +601 -0
  337. package/dist/v8/serialize.js.map +1 -0
  338. package/dist/ws/client.d.ts +25 -0
  339. package/dist/ws/client.js +203 -0
  340. package/dist/ws/client.js.map +1 -0
  341. package/dist/ws/control.d.ts +48 -0
  342. package/dist/ws/control.js +44 -0
  343. package/dist/ws/control.js.map +1 -0
  344. package/dist/ws/frames.d.ts +38 -0
  345. package/dist/ws/frames.js +39 -0
  346. package/dist/ws/frames.js.map +1 -0
  347. package/dist/ws/server.d.ts +99 -0
  348. package/dist/ws/server.js +295 -0
  349. package/dist/ws/server.js.map +1 -0
  350. package/dist/ws/sw-connector.d.ts +10 -0
  351. package/dist/ws/sw-connector.js +25 -0
  352. package/dist/ws/sw-connector.js.map +1 -0
  353. package/dist/ws/upgrade.d.ts +28 -0
  354. package/dist/ws/upgrade.js +75 -0
  355. package/dist/ws/upgrade.js.map +1 -0
  356. package/package.json +111 -3
  357. package/vendor/celld/LICENSE +202 -0
  358. package/vendor/celld/kv.js +1131 -0
  359. package/vendor/celld/queues.js +1656 -0
  360. package/vendor/celld/workflows.js +1610 -0
  361. package/vendor/html-rewriter-wasm/html_rewriter.js +925 -0
  362. package/vendor/html-rewriter-wasm/html_rewriter_bg.wasm +0 -0
  363. package/vendor/miniflare/d1-api.js +738 -0
  364. package/vendor/miniflare/d1-database.js +6978 -0
  365. package/vendor/miniflare/kv-namespace.js +3061 -0
@@ -0,0 +1,555 @@
1
+ import { createHash, createHmac, randomBytes, timingSafeEqual } from "node:crypto";
2
+ import { createServer } from "node:http";
3
+ import { toAnotherNode } from "../core/handles.js";
4
+ import { deserialize, serialize } from "../v8/serialize.js";
5
+ import { createWebSocketClass } from "../ws/client.js";
6
+ import { CellsResponse, takeClientPort, WebSocketPair } from "../ws/server.js";
7
+ import { withUpgrade } from "../ws/upgrade.js";
8
+ /**
9
+ * celld's peer protocol (peer_auth.rs, main/peer_tunnel.rs, protocol 5) for a cellb node
10
+ * hosted in Node, so celld nodes can route a cell's requests to it when it owns the cell.
11
+ *
12
+ * Authentication: every peer request carries an HMAC-SHA-256 over
13
+ * "cells-peer-request-v1\n5\n<method>\n<path?query>\n<sha256(body)>\n<source>\n<target>\n<ts>\n<nonce>"
14
+ * keyed by the fleet secret in `fleet/peer-auth.json`, with headers x-cells-peer-{version,
15
+ * source,target,timestamp,nonce,body-sha256,signature}; ±30 s clock window, nonce replay cache,
16
+ * and the target must be this node.
17
+ *
18
+ * Tunnel: `GET /peer/tunnel` with `Upgrade: celld-tunnel` (kind `do` or `rpc`) is answered with
19
+ * 101; then the connection carries plain HTTP/1.1 requests, one call each, with control headers
20
+ * x-cells-scope (the cell, "<Class>:<idhex>"), x-cells-do-name, x-cells-request-id:
21
+ * do — the application request as is; the reply streams back.
22
+ * rpc — POST, method in x-cells-rpc-method, arguments V8-serialized (an array) or JSON; the
23
+ * reply is the V8-serialized result, or a tagged error (0, then [error, props]).
24
+ * A cell this node does not own answers 409 with `x-cells-route-error: stale-owner`, so celld
25
+ * re-resolves the owner.
26
+ */
27
+ const PROTOCOL = "5";
28
+ const DOMAIN = "cells-peer-request-v1";
29
+ const CLOCK_WINDOW_MS = 30_000;
30
+ const PEER_HEADERS = {
31
+ version: "x-cells-peer-version",
32
+ source: "x-cells-peer-source",
33
+ target: "x-cells-peer-target",
34
+ timestamp: "x-cells-peer-timestamp",
35
+ nonce: "x-cells-peer-nonce",
36
+ bodySha: "x-cells-peer-body-sha256",
37
+ signature: "x-cells-peer-signature",
38
+ };
39
+ const CONTROL = [
40
+ "x-cells-scope",
41
+ "x-cells-do-name",
42
+ "x-cells-request-id",
43
+ "x-cells-capacity-handoff",
44
+ ];
45
+ /** The fleet's peer secret (celld creates it in the bucket). */
46
+ export async function loadPeerKey(store) {
47
+ const o = await store.get("fleet/peer-auth.json");
48
+ if (!o)
49
+ throw new Error("the fleet has no peer authentication secret; start a celld node first");
50
+ const { version, key } = JSON.parse(new TextDecoder().decode(o.body));
51
+ if (version !== 1 || !/^[0-9a-f]{64}$/.test(key))
52
+ throw new Error("unexpected fleet/peer-auth.json");
53
+ return Uint8Array.from(Buffer.from(key, "hex"));
54
+ }
55
+ const sha256hex = (b) => createHash("sha256").update(b).digest("hex");
56
+ const mac = (key, c) => createHmac("sha256", key)
57
+ .update(`${DOMAIN}\n${PROTOCOL}\n${c.method}\n${c.path}\n${c.bodySha}\n${c.source}\n${c.target}\n${c.ts}\n${c.nonce}`)
58
+ .digest();
59
+ /** Headers that sign one peer request from `source` to `target`. */
60
+ export function signPeerRequest(key, source, target, method, pathAndQuery, body = new Uint8Array()) {
61
+ const ts = String(Date.now());
62
+ const nonce = randomBytes(16).toString("hex");
63
+ const bodySha = sha256hex(body);
64
+ const signature = mac(key, {
65
+ method,
66
+ path: pathAndQuery,
67
+ bodySha,
68
+ source,
69
+ target,
70
+ ts,
71
+ nonce,
72
+ }).toString("hex");
73
+ return {
74
+ [PEER_HEADERS.version]: PROTOCOL,
75
+ [PEER_HEADERS.source]: source,
76
+ [PEER_HEADERS.target]: target,
77
+ [PEER_HEADERS.timestamp]: ts,
78
+ [PEER_HEADERS.nonce]: nonce,
79
+ [PEER_HEADERS.bodySha]: bodySha,
80
+ [PEER_HEADERS.signature]: signature,
81
+ };
82
+ }
83
+ /** celld's verification; returns a status and message on failure. */
84
+ export function verifyPeerRequest(key, self, method, pathAndQuery, headers, body, seen) {
85
+ const h = (n) => (typeof headers[n] === "string" ? headers[n] : undefined);
86
+ const version = h(PEER_HEADERS.version);
87
+ if (version === undefined)
88
+ return { status: 401, message: "peer authentication failed" };
89
+ if (version !== PROTOCOL)
90
+ return { status: 426, message: "peer protocol version is incompatible" };
91
+ const [source, target, ts, nonce, bodySha, signature] = [
92
+ PEER_HEADERS.source,
93
+ PEER_HEADERS.target,
94
+ PEER_HEADERS.timestamp,
95
+ PEER_HEADERS.nonce,
96
+ PEER_HEADERS.bodySha,
97
+ PEER_HEADERS.signature,
98
+ ].map(h);
99
+ if (!source || !target || !ts || !nonce || !bodySha || !signature)
100
+ return { status: 401, message: "peer authentication failed" };
101
+ const now = Date.now();
102
+ if (!/^\d+$/.test(ts) || Math.abs(now - Number(ts)) > CLOCK_WINDOW_MS)
103
+ return { status: 401, message: "peer authentication failed" };
104
+ if (sha256hex(body) !== bodySha ||
105
+ !/^[0-9a-f]{32}$/.test(nonce) ||
106
+ !/^[0-9a-f]{64}$/.test(signature))
107
+ return { status: 401, message: "peer authentication failed" };
108
+ const expected = mac(key, { method, path: pathAndQuery, bodySha, source, target, ts, nonce });
109
+ if (!timingSafeEqual(expected, Buffer.from(signature, "hex")))
110
+ return { status: 401, message: "peer authentication failed" };
111
+ if (target !== self)
112
+ return { status: 409, message: "peer request targets a different node session", stale: true };
113
+ for (const [n, t] of seen)
114
+ if (now - t > 2 * CLOCK_WINDOW_MS)
115
+ seen.delete(n);
116
+ if (seen.has(nonce))
117
+ return { status: 409, message: "peer request replay rejected" };
118
+ seen.set(nonce, now);
119
+ return undefined;
120
+ }
121
+ const readBody = async (req) => {
122
+ const chunks = [];
123
+ for await (const c of req)
124
+ chunks.push(c);
125
+ return new Uint8Array(Buffer.concat(chunks));
126
+ };
127
+ /** The cell a scope names, as a stub of this runtime (undefined: not a class we host). */
128
+ function stubFor(runtime, scope, name) {
129
+ const m = /^([^:]+):([0-9a-f]{64})$/.exec(scope);
130
+ if (!m)
131
+ return undefined;
132
+ const binding = Object.entries(runtime.durableObjectBindings).find(([, cls]) => cls === m[1])?.[0];
133
+ if (!binding)
134
+ return undefined;
135
+ const ns = runtime.env[binding];
136
+ return name !== undefined ? ns.getByName(name) : ns.get(ns.idFromString(m[2]));
137
+ }
138
+ const notOwner = (e) => /owned by another|OwnedElsewhere|lease/i.test(String(e?.message ?? e)) ||
139
+ e?.name === "CellOwnedElsewhereError";
140
+ function reply(res, status, headers, body) {
141
+ res.writeHead(status, { [PEER_HEADERS.version]: PROTOCOL, ...headers });
142
+ res.end(body);
143
+ }
144
+ const stale = (res) => reply(res, 409, { "x-cells-route-error": "stale-owner", "content-type": "text/plain" }, "stale route");
145
+ /**
146
+ * Serves celld's peer tunnel for `runtime` on `host:port` (0: any free port). `node` is this
147
+ * node's name in the fleet (the same as celldBucket's `node`).
148
+ */
149
+ export async function startCelldPeerServer(opts) {
150
+ const key = await loadPeerKey(opts.store);
151
+ const seen = new Map();
152
+ const host = opts.host ?? "127.0.0.1";
153
+ const serveDo = async (req, res) => {
154
+ const scope = String(req.headers["x-cells-scope"] ?? "");
155
+ const name = req.headers["x-cells-do-name"];
156
+ const stub = stubFor(opts.runtime, scope, name);
157
+ if (!stub)
158
+ return reply(res, 400, {}, "malformed cell scope");
159
+ const headers = new Headers();
160
+ for (const [k, v] of Object.entries(req.headers))
161
+ if (typeof v === "string" && !CONTROL.includes(k))
162
+ headers.set(k, v);
163
+ const method = req.method ?? "GET";
164
+ const body = method === "GET" || method === "HEAD" ? undefined : await readBody(req);
165
+ const url = /^https?:\/\//.test(req.url ?? "")
166
+ ? req.url
167
+ : `http://${req.headers.host ?? "cell"}${req.url ?? "/"}`;
168
+ try {
169
+ const r = await stub.fetch(new Request(url, { method, headers, body }));
170
+ const out = {};
171
+ r.headers.forEach((v, k) => {
172
+ if (k !== "content-length" && k !== "transfer-encoding" && k !== "connection")
173
+ out[k] = v;
174
+ });
175
+ reply(res, r.status, out, new Uint8Array(await r.arrayBuffer()));
176
+ }
177
+ catch (e) {
178
+ if (notOwner(e))
179
+ return stale(res);
180
+ reply(res, 500, { "content-type": "text/plain" }, String(e?.message ?? e));
181
+ }
182
+ };
183
+ const serveRpc = async (req, res) => {
184
+ const scope = String(req.headers["x-cells-scope"] ?? "");
185
+ const stub = stubFor(opts.runtime, scope, req.headers["x-cells-do-name"]);
186
+ const method = req.headers["x-cells-rpc-method"];
187
+ if (!stub)
188
+ return reply(res, 400, {}, "malformed cell scope");
189
+ if (!method)
190
+ return reply(res, 400, {}, "RPC method header is missing");
191
+ const raw = await readBody(req);
192
+ const structured = req.headers["content-type"] === "application/octet-stream";
193
+ let args;
194
+ if (structured) {
195
+ if (raw[0] !== 0xff)
196
+ return reply(res, 501, {}, "RPC stubs cannot cross to cellb");
197
+ args = deserialize(raw);
198
+ }
199
+ else
200
+ args = JSON.parse(new TextDecoder().decode(raw));
201
+ try {
202
+ const result = await stub[method](...(Array.isArray(args) ? args : [args]));
203
+ if (structured)
204
+ reply(res, 200, { "content-type": "application/octet-stream" }, serialize(toAnotherNode(result)));
205
+ else
206
+ reply(res, 200, { "content-type": "application/json" }, JSON.stringify(result ?? null));
207
+ }
208
+ catch (e) {
209
+ if (notOwner(e))
210
+ return stale(res);
211
+ if (!structured)
212
+ return reply(res, 500, { "content-type": "text/plain" }, `RPC failed: ${String(e?.message ?? e)}`);
213
+ // celld's callee exception: tag 0, then [error, own properties incl. name]
214
+ const err = e instanceof Error ? e : new Error(String(e));
215
+ const props = e instanceof Error ? { ...e, name: e.name } : { name: "Error" };
216
+ const sc = serialize([err, props]);
217
+ const tagged = new Uint8Array(sc.length + 1);
218
+ tagged.set(sc, 1);
219
+ reply(res, 200, { "content-type": "application/octet-stream" }, tagged);
220
+ }
221
+ };
222
+ // One inner HTTP/1.1 server per tunnel kind: an upgraded socket becomes its connection.
223
+ // celld's inner RPC requests carry no Host header: Node would answer 400 by default.
224
+ const inner = {
225
+ do: createServer({ requireHostHeader: false }, (q, s) => void serveDo(q, s)),
226
+ rpc: createServer({ requireHostHeader: false }, (q, s) => void serveRpc(q, s)),
227
+ };
228
+ for (const s of Object.values(inner))
229
+ s.keepAliveTimeout = 0;
230
+ // A tunneled WebSocket (celld: the client's own handshake crosses the tunnel and the owner
231
+ // answers it): the cell's 101 + webSocket is bridged to the raw connection, framed by `ws`.
232
+ const { WebSocketServer } = await import("ws");
233
+ const wss = new WebSocketServer({ noServer: true });
234
+ inner.do.on("upgrade", async (req, socket, head) => {
235
+ const fail = (status, body, extra = {}) => {
236
+ const lines = [
237
+ `HTTP/1.1 ${status} ${status === 409 ? "Conflict" : "Error"}`,
238
+ `${PEER_HEADERS.version}: ${PROTOCOL}`,
239
+ `content-length: ${Buffer.byteLength(body)}`,
240
+ "connection: close",
241
+ ];
242
+ for (const [k, v] of Object.entries(extra))
243
+ lines.push(`${k}: ${v}`);
244
+ socket.end(`${lines.join("\r\n")}\r\n\r\n${body}`);
245
+ };
246
+ const stub = stubFor(opts.runtime, String(req.headers["x-cells-scope"] ?? ""), req.headers["x-cells-do-name"]);
247
+ if (!stub)
248
+ return fail(400, "malformed cell scope");
249
+ const headers = new Headers();
250
+ for (const [k, v] of Object.entries(req.headers))
251
+ if (typeof v === "string" && !CONTROL.includes(k))
252
+ headers.set(k, v);
253
+ const url = /^https?:\/\//.test(req.url ?? "")
254
+ ? req.url
255
+ : `http://${req.headers.host ?? "cell"}${req.url ?? "/"}`;
256
+ const protocols = req.headers["sec-websocket-protocol"];
257
+ let res;
258
+ try {
259
+ res = await stub.fetch(withUpgrade(new Request(url, { headers }), "websocket", protocols ? { "Sec-WebSocket-Protocol": protocols } : undefined));
260
+ }
261
+ catch (e) {
262
+ return notOwner(e)
263
+ ? fail(409, "stale route", { "x-cells-route-error": "stale-owner" })
264
+ : fail(500, String(e?.message ?? e));
265
+ }
266
+ if (res.status !== 101 || !res.webSocket)
267
+ return fail(res.status, await res.text());
268
+ const port = takeClientPort(res.webSocket);
269
+ const WS = createWebSocketClass(async () => ({
270
+ port,
271
+ protocol: res.headers.get("Sec-WebSocket-Protocol") ?? undefined,
272
+ }));
273
+ const cell = new WS("ws://cell/");
274
+ cell.binaryType = "arraybuffer";
275
+ const pending = [];
276
+ let open = false;
277
+ wss.handleUpgrade(req, socket, head, (client) => {
278
+ cell.onopen = () => {
279
+ open = true;
280
+ for (const m of pending.splice(0))
281
+ cell.send(m);
282
+ };
283
+ client.on("message", (data, isBinary) => {
284
+ const m = isBinary ? new Uint8Array(data).buffer : data.toString();
285
+ if (open)
286
+ cell.send(m);
287
+ else
288
+ pending.push(m);
289
+ });
290
+ cell.onmessage = (ev) => client.send(ev.data instanceof ArrayBuffer ? Buffer.from(ev.data) : ev.data);
291
+ client.on("close", (code, reason) => cell.close(code >= 1000 && code < 5000 && code !== 1005 && code !== 1006 ? code : 1000, reason.toString()));
292
+ cell.onclose = (ev) => client.close(ev.code >= 1000 && ev.code !== 1005 && ev.code !== 1006 ? ev.code : 1000, ev.reason);
293
+ });
294
+ });
295
+ const server = createServer(async (req, res) => {
296
+ if (req.url === "/peer/probe" && req.method === "GET" && opts.probe) {
297
+ const denied = verifyPeerRequest(key, opts.node, "GET", "/peer/probe", req.headers, new Uint8Array(), seen);
298
+ if (denied)
299
+ return reply(res, denied.status, { "content-type": "text/plain" }, denied.message);
300
+ try {
301
+ const answer = await opts.probe(String(req.headers["x-cells-probe-challenge"] ?? ""));
302
+ return reply(res, 200, { "content-type": "application/json" }, JSON.stringify(answer));
303
+ }
304
+ catch (e) {
305
+ return reply(res, 400, { "content-type": "text/plain" }, String(e?.message ?? e));
306
+ }
307
+ }
308
+ reply(res, 404, {}, "not found");
309
+ });
310
+ server.on("upgrade", (req, socket, head) => {
311
+ const path = req.url ?? "/";
312
+ const refuse = (status, message, extra = {}) => {
313
+ const lines = [
314
+ `HTTP/1.1 ${status} ${message}`,
315
+ `${PEER_HEADERS.version}: ${PROTOCOL}`,
316
+ "connection: close",
317
+ "content-length: 0",
318
+ ];
319
+ for (const [k, v] of Object.entries(extra))
320
+ lines.push(`${k}: ${v}`);
321
+ socket.end(`${lines.join("\r\n")}\r\n\r\n`);
322
+ };
323
+ if (path !== "/peer/tunnel" || req.headers.upgrade !== "celld-tunnel")
324
+ return refuse(404, "Not Found");
325
+ const denied = verifyPeerRequest(key, opts.node, req.method ?? "GET", path, req.headers, new Uint8Array(), seen);
326
+ if (denied)
327
+ return refuse(denied.status, denied.message, denied.stale ? { "x-cells-route-error": "stale-owner" } : {});
328
+ if (req.headers["x-cells-tunnel-version"] !== "5")
329
+ return refuse(426, "Upgrade Required");
330
+ const kind = req.headers["x-cells-tunnel-kind"];
331
+ if (kind !== "do" && kind !== "rpc")
332
+ return refuse(400, "Bad Request");
333
+ socket.write([
334
+ "HTTP/1.1 101 Switching Protocols",
335
+ "upgrade: celld-tunnel",
336
+ "connection: upgrade",
337
+ "x-cells-tunnel-version: 5",
338
+ `${PEER_HEADERS.version}: ${PROTOCOL}`,
339
+ ].join("\r\n") + "\r\n\r\n");
340
+ if (head?.length)
341
+ socket.unshift(head);
342
+ inner[kind].emit("connection", socket);
343
+ });
344
+ await new Promise((r) => server.listen(opts.port ?? 0, host, () => r()));
345
+ const port = server.address().port;
346
+ return {
347
+ addr: `${host}:${port}`,
348
+ close: () => new Promise((r) => {
349
+ server.closeAllConnections?.();
350
+ for (const s of Object.values(inner))
351
+ s.closeAllConnections?.();
352
+ server.close(() => r());
353
+ }),
354
+ };
355
+ }
356
+ /**
357
+ * The calling half (celld's node A): open a signed tunnel to the owner node and send one call
358
+ * through it — `fetch` on a `do` tunnel, JS RPC on an `rpc` tunnel (V8-serialized arguments;
359
+ * the reply decoded as celld encodes it, a callee exception rethrown with its properties).
360
+ */
361
+ /** A signed `celld-tunnel` upgrade to the owner node: the raw connection after its 101. */
362
+ async function openTunnel(key, source, owner, kind) {
363
+ const { request } = await import("node:http");
364
+ const [host, port] = [
365
+ owner.addr.slice(0, owner.addr.lastIndexOf(":")),
366
+ Number(owner.addr.slice(owner.addr.lastIndexOf(":") + 1)),
367
+ ];
368
+ const socket = await new Promise((resolve, reject) => {
369
+ const req = request({
370
+ host,
371
+ port,
372
+ path: "/peer/tunnel",
373
+ method: "GET",
374
+ headers: {
375
+ upgrade: "celld-tunnel",
376
+ connection: "upgrade",
377
+ "x-cells-tunnel-version": "5",
378
+ "x-cells-tunnel-kind": kind,
379
+ ...signPeerRequest(key, source, owner.node, "GET", "/peer/tunnel"),
380
+ },
381
+ });
382
+ req.on("upgrade", (_res, sock) => resolve(sock));
383
+ req.on("response", (res) => reject(Object.assign(new Error(`peer tunnel refused: ${res.statusCode}`), {
384
+ stale: res.headers["x-cells-route-error"] === "stale-owner",
385
+ })));
386
+ req.on("error", reject);
387
+ req.end();
388
+ });
389
+ return socket;
390
+ }
391
+ async function tunnelCall(key, source, owner, kind, inner) {
392
+ const { request } = await import("node:http");
393
+ const socket = await openTunnel(key, source, owner, kind);
394
+ try {
395
+ return await new Promise((resolve, reject) => {
396
+ const req = request(
397
+ // no agent: the request runs on the upgraded socket itself
398
+ {
399
+ createConnection: () => socket,
400
+ method: inner.method,
401
+ path: inner.path,
402
+ headers: inner.headers,
403
+ }, async (res) => {
404
+ const chunks = [];
405
+ for await (const c of res)
406
+ chunks.push(c);
407
+ const headers = {};
408
+ for (const [k, v] of Object.entries(res.headers))
409
+ if (typeof v === "string")
410
+ headers[k] = v;
411
+ resolve({
412
+ status: res.statusCode ?? 500,
413
+ headers,
414
+ body: new Uint8Array(Buffer.concat(chunks)),
415
+ });
416
+ });
417
+ req.on("error", reject);
418
+ req.end(inner.body);
419
+ });
420
+ }
421
+ finally {
422
+ socket.destroy();
423
+ }
424
+ }
425
+ /**
426
+ * Routing to cells celld nodes own, for CellRuntimeOptions.peers: `ownerOf` reads the cell's
427
+ * own.json, `endpoint` reaches the owner's address from its node record through the tunnel.
428
+ */
429
+ export function celldPeers(opts) {
430
+ let key;
431
+ const json = async (k) => {
432
+ const o = await opts.store.get(k);
433
+ return o ? JSON.parse(new TextDecoder().decode(o.body)) : undefined;
434
+ };
435
+ const staleError = (cellKey) => Object.assign(new Error(`${cellKey} is owned by another node`), {
436
+ name: "CellOwnedElsewhereError",
437
+ });
438
+ return {
439
+ async ownerOf(cellKey) {
440
+ const own = await json(`cells/${cellKey.replace("/", ":")}/own.json`);
441
+ return own?.node && own.node !== opts.node ? own.node : undefined;
442
+ },
443
+ link() {
444
+ throw new Error("celld owners are reached through endpoint()");
445
+ },
446
+ async endpoint(owner, cellKey, name) {
447
+ const lease = await json(`nodes/${owner}.json`);
448
+ if (!lease?.addr || lease.expires_ms <= Date.now())
449
+ return undefined;
450
+ key ??= loadPeerKey(opts.store);
451
+ const k = await key;
452
+ const target = { node: owner, addr: lease.addr };
453
+ const scope = cellKey.replace("/", ":");
454
+ const control = (h) => ({
455
+ ...h,
456
+ "x-cells-scope": scope,
457
+ ...(name !== undefined ? { "x-cells-do-name": name } : {}),
458
+ });
459
+ // A WebSocket to a cell celld owns: the client handshake crosses a `do` tunnel and `ws`
460
+ // speaks the frames on it; the caller gets a 101 with a WebSocketPair end bridged to it.
461
+ const tunnelWebSocket = async (req, url) => {
462
+ const socket = await openTunnel(k, opts.node, target, "do");
463
+ const { WebSocket: WsClient } = await import("ws");
464
+ const protocols = req.headers
465
+ .get("sec-websocket-protocol")
466
+ ?.split(",")
467
+ .map((p) => p.trim())
468
+ .filter(Boolean);
469
+ const remote = new WsClient(`ws://${url.host}${url.pathname}${url.search}`, protocols, {
470
+ createConnection: () => socket,
471
+ headers: control({}),
472
+ });
473
+ await new Promise((resolve, reject) => {
474
+ remote.once("open", () => resolve());
475
+ remote.once("unexpected-response", (_q, res) => reject(res.headers["x-cells-route-error"] === "stale-owner"
476
+ ? staleError(cellKey)
477
+ : new Error(`WebSocket through the tunnel refused: ${res.statusCode}`)));
478
+ remote.once("error", reject);
479
+ });
480
+ const pair = new WebSocketPair();
481
+ const [client, server] = [pair[0], pair[1]];
482
+ server.accept();
483
+ server.addEventListener("message", (e) => remote.send(e.data));
484
+ remote.on("message", (d, isBinary) => server.send(isBinary ? new Uint8Array(d) : d.toString()));
485
+ const code = (c) => (c >= 1000 && c !== 1005 && c !== 1006 ? c : 1000);
486
+ server.addEventListener("close", (e) => remote.close(code(e.code), e.reason));
487
+ remote.on("close", (c, reason) => server.close(code(c), reason.toString()));
488
+ return new CellsResponse(null, {
489
+ status: 101,
490
+ webSocket: client,
491
+ headers: remote.protocol ? { "Sec-WebSocket-Protocol": remote.protocol } : {},
492
+ });
493
+ };
494
+ return {
495
+ async fetch(req) {
496
+ const url = new URL(req.url);
497
+ if (req.headers.get("upgrade")?.toLowerCase() === "websocket")
498
+ return tunnelWebSocket(req, url);
499
+ const headers = {};
500
+ req.headers.forEach((v, h) => {
501
+ if (!h.startsWith("x-cells-"))
502
+ headers[h] = v;
503
+ });
504
+ headers.host ??= url.host;
505
+ const body = req.method === "GET" || req.method === "HEAD"
506
+ ? undefined
507
+ : new Uint8Array(await req.arrayBuffer());
508
+ const r = await tunnelCall(k, opts.node, target, "do", {
509
+ method: req.method,
510
+ path: url.pathname + url.search,
511
+ headers: control(headers),
512
+ body,
513
+ });
514
+ if (r.status === 409 && r.headers["x-cells-route-error"] === "stale-owner")
515
+ throw staleError(cellKey);
516
+ const out = new Headers();
517
+ for (const [h, v] of Object.entries(r.headers))
518
+ if (!h.startsWith("x-cells-"))
519
+ out.set(h, v);
520
+ return new Response(r.status === 204 || r.status === 304 ? null : r.body, {
521
+ status: r.status,
522
+ headers: out,
523
+ });
524
+ },
525
+ async call(method, args) {
526
+ const body = serialize(toAnotherNode(args));
527
+ const r = await tunnelCall(k, opts.node, target, "rpc", {
528
+ method: "POST",
529
+ path: "/",
530
+ headers: control({
531
+ "x-cells-rpc-method": method,
532
+ "content-type": "application/octet-stream",
533
+ "content-length": String(body.length),
534
+ }),
535
+ body,
536
+ });
537
+ if (r.status === 409 && r.headers["x-cells-route-error"] === "stale-owner")
538
+ throw staleError(cellKey);
539
+ if (r.status !== 200)
540
+ throw new Error(`remote RPC failed with ${r.status}: ${new TextDecoder().decode(r.body)}`);
541
+ if (r.body[0] === 0xff)
542
+ return deserialize(r.body);
543
+ if (r.body[0] === 0) {
544
+ const [error, props] = deserialize(r.body.subarray(1));
545
+ if (error instanceof Error)
546
+ Object.assign(error, props, { remote: true });
547
+ throw error;
548
+ }
549
+ throw new Error("RPC stubs cannot cross from celld to cellb");
550
+ },
551
+ };
552
+ },
553
+ };
554
+ }
555
+ //# sourceMappingURL=celld-peer.js.map