@procedures/client 0.2.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (369) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/README.md +77 -44
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/adapters/http/client/transport.d.ts.map +1 -1
  5. package/dist/adapters/http/client/transport.js +35 -3
  6. package/dist/adapters/http/client/transport.js.map +1 -1
  7. package/dist/adapters/http/client/types.d.ts +3 -2
  8. package/dist/adapters/http/client/types.d.ts.map +1 -1
  9. package/dist/adapters/http/server/transport.d.ts +2 -2
  10. package/dist/adapters/http/server/transport.d.ts.map +1 -1
  11. package/dist/adapters/http/server/transport.js +54 -22
  12. package/dist/adapters/http/server/transport.js.map +1 -1
  13. package/dist/adapters/http/shared/headers.d.ts +1 -1
  14. package/dist/adapters/http/shared/headers.d.ts.map +1 -1
  15. package/dist/adapters/http/shared/headers.js +7 -6
  16. package/dist/adapters/http/shared/headers.js.map +1 -1
  17. package/dist/adapters/local/client/transport.d.ts +3 -0
  18. package/dist/adapters/local/client/transport.d.ts.map +1 -1
  19. package/dist/adapters/local/client/transport.js +67 -6
  20. package/dist/adapters/local/client/transport.js.map +1 -1
  21. package/dist/adapters/local/client/types.d.ts +15 -0
  22. package/dist/adapters/local/client/types.d.ts.map +1 -1
  23. package/dist/adapters/local/client/types.js.map +1 -1
  24. package/dist/adapters/mock/client/transport.d.ts +3 -2
  25. package/dist/adapters/mock/client/transport.d.ts.map +1 -1
  26. package/dist/adapters/mock/client/transport.js +8 -5
  27. package/dist/adapters/mock/client/transport.js.map +1 -1
  28. package/dist/adapters/mock/client/types.d.ts +7 -6
  29. package/dist/adapters/mock/client/types.d.ts.map +1 -1
  30. package/dist/adapters/port/transport.d.ts +62 -0
  31. package/dist/adapters/port/transport.d.ts.map +1 -0
  32. package/dist/adapters/port/transport.js +94 -0
  33. package/dist/adapters/port/transport.js.map +1 -0
  34. package/dist/adapters/websocket/client/index.d.ts +1 -1
  35. package/dist/adapters/websocket/client/index.d.ts.map +1 -1
  36. package/dist/adapters/websocket/client/index.js.map +1 -1
  37. package/dist/adapters/websocket/client/node.d.ts +30 -0
  38. package/dist/adapters/websocket/client/node.d.ts.map +1 -0
  39. package/dist/adapters/websocket/client/node.js +32 -0
  40. package/dist/adapters/websocket/client/node.js.map +1 -0
  41. package/dist/adapters/websocket/client/transport.d.ts +47 -7
  42. package/dist/adapters/websocket/client/transport.d.ts.map +1 -1
  43. package/dist/adapters/websocket/client/transport.js +229 -75
  44. package/dist/adapters/websocket/client/transport.js.map +1 -1
  45. package/dist/adapters/websocket/client/types.d.ts +71 -21
  46. package/dist/adapters/websocket/client/types.d.ts.map +1 -1
  47. package/dist/adapters/websocket/client/types.js.map +1 -1
  48. package/dist/adapters/websocket/server/transport.d.ts +65 -24
  49. package/dist/adapters/websocket/server/transport.d.ts.map +1 -1
  50. package/dist/adapters/websocket/server/transport.js +192 -263
  51. package/dist/adapters/websocket/server/transport.js.map +1 -1
  52. package/dist/adapters/websocket/server/types.d.ts +20 -1
  53. package/dist/adapters/websocket/server/types.d.ts.map +1 -1
  54. package/dist/adapters/websocket/shared/rpc.d.ts +129 -0
  55. package/dist/adapters/websocket/shared/rpc.d.ts.map +1 -0
  56. package/dist/adapters/websocket/shared/rpc.js +425 -0
  57. package/dist/adapters/websocket/shared/rpc.js.map +1 -0
  58. package/dist/browser.d.ts +29 -7
  59. package/dist/browser.d.ts.map +1 -1
  60. package/dist/browser.js +26 -3
  61. package/dist/browser.js.map +1 -1
  62. package/dist/client/call-types.d.ts +10 -10
  63. package/dist/client/call-types.d.ts.map +1 -1
  64. package/dist/client/call-types.js +1 -6
  65. package/dist/client/call-types.js.map +1 -1
  66. package/dist/client/client.d.ts +6 -1
  67. package/dist/client/client.d.ts.map +1 -1
  68. package/dist/client/client.js +23 -9
  69. package/dist/client/client.js.map +1 -1
  70. package/dist/client/deadline.d.ts +38 -0
  71. package/dist/client/deadline.d.ts.map +1 -0
  72. package/dist/client/deadline.js +60 -0
  73. package/dist/client/deadline.js.map +1 -0
  74. package/dist/client/errors/factory.d.ts.map +1 -1
  75. package/dist/client/errors/factory.js +11 -7
  76. package/dist/client/errors/factory.js.map +1 -1
  77. package/dist/client/errors/http-errors.d.ts.map +1 -1
  78. package/dist/client/errors/http-errors.js +6 -0
  79. package/dist/client/errors/http-errors.js.map +1 -1
  80. package/dist/client/errors/index.d.ts +1 -1
  81. package/dist/client/errors/index.js +1 -1
  82. package/dist/client/errors/registry.d.ts +2 -1
  83. package/dist/client/errors/registry.d.ts.map +1 -1
  84. package/dist/client/errors/registry.js +72 -22
  85. package/dist/client/errors/registry.js.map +1 -1
  86. package/dist/client/index.d.ts +9 -2
  87. package/dist/client/index.d.ts.map +1 -1
  88. package/dist/client/index.js +8 -2
  89. package/dist/client/index.js.map +1 -1
  90. package/dist/client/middleware/cache.d.ts +19 -5
  91. package/dist/client/middleware/cache.d.ts.map +1 -1
  92. package/dist/client/middleware/cache.js +106 -18
  93. package/dist/client/middleware/cache.js.map +1 -1
  94. package/dist/client/middleware/circuit-breaker.d.ts +28 -10
  95. package/dist/client/middleware/circuit-breaker.d.ts.map +1 -1
  96. package/dist/client/middleware/circuit-breaker.js +35 -24
  97. package/dist/client/middleware/circuit-breaker.js.map +1 -1
  98. package/dist/client/middleware/contexts.d.ts +16 -10
  99. package/dist/client/middleware/contexts.d.ts.map +1 -1
  100. package/dist/client/middleware/contexts.js.map +1 -1
  101. package/dist/client/middleware/items.d.ts +31 -2
  102. package/dist/client/middleware/items.d.ts.map +1 -1
  103. package/dist/client/middleware/items.js +86 -6
  104. package/dist/client/middleware/items.js.map +1 -1
  105. package/dist/client/middleware/lru.d.ts +2 -0
  106. package/dist/client/middleware/lru.d.ts.map +1 -1
  107. package/dist/client/middleware/lru.js +11 -0
  108. package/dist/client/middleware/lru.js.map +1 -1
  109. package/dist/client/middleware/rate-limit.d.ts +7 -6
  110. package/dist/client/middleware/rate-limit.d.ts.map +1 -1
  111. package/dist/client/middleware/rate-limit.js +9 -7
  112. package/dist/client/middleware/rate-limit.js.map +1 -1
  113. package/dist/client/middleware/resilience.d.ts +61 -0
  114. package/dist/client/middleware/resilience.d.ts.map +1 -0
  115. package/dist/client/middleware/resilience.js +59 -0
  116. package/dist/client/middleware/resilience.js.map +1 -0
  117. package/dist/client/middleware/retry.d.ts +45 -11
  118. package/dist/client/middleware/retry.d.ts.map +1 -1
  119. package/dist/client/middleware/retry.js +102 -22
  120. package/dist/client/middleware/retry.js.map +1 -1
  121. package/dist/client/middleware/timeout.d.ts +15 -12
  122. package/dist/client/middleware/timeout.d.ts.map +1 -1
  123. package/dist/client/middleware/timeout.js +48 -46
  124. package/dist/client/middleware/timeout.js.map +1 -1
  125. package/dist/client/middleware/tracing.d.ts.map +1 -1
  126. package/dist/client/middleware/tracing.js +11 -3
  127. package/dist/client/middleware/tracing.js.map +1 -1
  128. package/dist/client/types.d.ts +9 -1
  129. package/dist/client/types.d.ts.map +1 -1
  130. package/dist/client/types.js.map +1 -1
  131. package/dist/clock.d.ts +19 -0
  132. package/dist/clock.d.ts.map +1 -0
  133. package/dist/clock.js +18 -0
  134. package/dist/clock.js.map +1 -0
  135. package/dist/duration.d.ts +37 -0
  136. package/dist/duration.d.ts.map +1 -0
  137. package/dist/duration.js +44 -0
  138. package/dist/duration.js.map +1 -0
  139. package/dist/index.d.ts +4 -0
  140. package/dist/index.d.ts.map +1 -1
  141. package/dist/index.js +4 -0
  142. package/dist/index.js.map +1 -1
  143. package/dist/machines.d.ts +90 -0
  144. package/dist/machines.d.ts.map +1 -0
  145. package/dist/machines.js +127 -0
  146. package/dist/machines.js.map +1 -0
  147. package/dist/node.d.ts +11 -0
  148. package/dist/node.d.ts.map +1 -0
  149. package/dist/node.js +10 -0
  150. package/dist/node.js.map +1 -0
  151. package/dist/procedures/capability.d.ts +3 -6
  152. package/dist/procedures/capability.d.ts.map +1 -1
  153. package/dist/procedures/capability.js +7 -8
  154. package/dist/procedures/capability.js.map +1 -1
  155. package/dist/procedures/collection/index.d.ts +3 -3
  156. package/dist/procedures/collection/index.d.ts.map +1 -1
  157. package/dist/procedures/collection/index.js +1 -1
  158. package/dist/procedures/collection/index.js.map +1 -1
  159. package/dist/procedures/collection/procedures.d.ts.map +1 -1
  160. package/dist/procedures/collection/procedures.js +49 -1
  161. package/dist/procedures/collection/procedures.js.map +1 -1
  162. package/dist/procedures/collection/schemas.d.ts +33 -0
  163. package/dist/procedures/collection/schemas.d.ts.map +1 -1
  164. package/dist/procedures/collection/schemas.js +68 -0
  165. package/dist/procedures/collection/schemas.js.map +1 -1
  166. package/dist/procedures/collection/storage.d.ts +37 -0
  167. package/dist/procedures/collection/storage.d.ts.map +1 -1
  168. package/dist/procedures/core/array.d.ts +1 -1
  169. package/dist/procedures/core/array.d.ts.map +1 -1
  170. package/dist/procedures/core/array.js +81 -29
  171. package/dist/procedures/core/array.js.map +1 -1
  172. package/dist/procedures/core/index.d.ts.map +1 -1
  173. package/dist/procedures/core/index.js +17 -2
  174. package/dist/procedures/core/index.js.map +1 -1
  175. package/dist/procedures/core/logic.js +1 -1
  176. package/dist/procedures/core/logic.js.map +1 -1
  177. package/dist/procedures/core/math.d.ts.map +1 -1
  178. package/dist/procedures/core/math.js +5 -1
  179. package/dist/procedures/core/math.js.map +1 -1
  180. package/dist/procedures/core/meta.d.ts.map +1 -1
  181. package/dist/procedures/core/meta.js +43 -8
  182. package/dist/procedures/core/meta.js.map +1 -1
  183. package/dist/procedures/core/object.d.ts.map +1 -1
  184. package/dist/procedures/core/object.js +42 -13
  185. package/dist/procedures/core/object.js.map +1 -1
  186. package/dist/procedures/core/operands.d.ts.map +1 -1
  187. package/dist/procedures/core/operands.js +6 -1
  188. package/dist/procedures/core/operands.js.map +1 -1
  189. package/dist/procedures/core/string.d.ts.map +1 -1
  190. package/dist/procedures/core/string.js +4 -2
  191. package/dist/procedures/core/string.js.map +1 -1
  192. package/dist/procedures/core/type.d.ts.map +1 -1
  193. package/dist/procedures/core/type.js +4 -2
  194. package/dist/procedures/core/type.js.map +1 -1
  195. package/dist/procedures/define-procedure.d.ts +19 -7
  196. package/dist/procedures/define-procedure.d.ts.map +1 -1
  197. package/dist/procedures/define-procedure.js +57 -17
  198. package/dist/procedures/define-procedure.js.map +1 -1
  199. package/dist/procedures/discovery.d.ts +4 -6
  200. package/dist/procedures/discovery.d.ts.map +1 -1
  201. package/dist/procedures/discovery.js +4 -6
  202. package/dist/procedures/discovery.js.map +1 -1
  203. package/dist/procedures/effects.d.ts +16 -0
  204. package/dist/procedures/effects.d.ts.map +1 -1
  205. package/dist/procedures/effects.js +33 -0
  206. package/dist/procedures/effects.js.map +1 -1
  207. package/dist/procedures/idempotency.d.ts +73 -0
  208. package/dist/procedures/idempotency.d.ts.map +1 -0
  209. package/dist/procedures/idempotency.js +131 -0
  210. package/dist/procedures/idempotency.js.map +1 -0
  211. package/dist/procedures/index.d.ts +7 -3
  212. package/dist/procedures/index.d.ts.map +1 -1
  213. package/dist/procedures/index.js +6 -2
  214. package/dist/procedures/index.js.map +1 -1
  215. package/dist/procedures/interceptors.d.ts +17 -4
  216. package/dist/procedures/interceptors.d.ts.map +1 -1
  217. package/dist/procedures/interceptors.js +18 -7
  218. package/dist/procedures/interceptors.js.map +1 -1
  219. package/dist/procedures/invoke.d.ts +15 -3
  220. package/dist/procedures/invoke.d.ts.map +1 -1
  221. package/dist/procedures/invoke.js +8 -3
  222. package/dist/procedures/invoke.js.map +1 -1
  223. package/dist/procedures/manifest.d.ts +83 -0
  224. package/dist/procedures/manifest.d.ts.map +1 -0
  225. package/dist/procedures/manifest.js +90 -0
  226. package/dist/procedures/manifest.js.map +1 -0
  227. package/dist/procedures/ref.d.ts +4 -2
  228. package/dist/procedures/ref.d.ts.map +1 -1
  229. package/dist/procedures/ref.js +2 -1
  230. package/dist/procedures/ref.js.map +1 -1
  231. package/dist/procedures/runtime-programs.d.ts +19 -0
  232. package/dist/procedures/runtime-programs.d.ts.map +1 -0
  233. package/dist/procedures/runtime-programs.js +24 -0
  234. package/dist/procedures/runtime-programs.js.map +1 -0
  235. package/dist/procedures/types.d.ts +16 -0
  236. package/dist/procedures/types.d.ts.map +1 -1
  237. package/dist/procedures/types.js.map +1 -1
  238. package/dist/protocol.d.ts +47 -0
  239. package/dist/protocol.d.ts.map +1 -0
  240. package/dist/protocol.js +68 -0
  241. package/dist/protocol.js.map +1 -0
  242. package/dist/server/host-policy.d.ts +4 -3
  243. package/dist/server/host-policy.d.ts.map +1 -1
  244. package/dist/server/host-policy.js +6 -3
  245. package/dist/server/host-policy.js.map +1 -1
  246. package/dist/server/host-procedures.d.ts +31 -0
  247. package/dist/server/host-procedures.d.ts.map +1 -0
  248. package/dist/server/host-procedures.js +75 -0
  249. package/dist/server/host-procedures.js.map +1 -0
  250. package/dist/server/index.d.ts +3 -3
  251. package/dist/server/index.d.ts.map +1 -1
  252. package/dist/server/index.js +1 -1
  253. package/dist/server/index.js.map +1 -1
  254. package/dist/server/procedure-server.d.ts +112 -5
  255. package/dist/server/procedure-server.d.ts.map +1 -1
  256. package/dist/server/procedure-server.js +273 -19
  257. package/dist/server/procedure-server.js.map +1 -1
  258. package/dist/server/request-auth.d.ts +19 -0
  259. package/dist/server/request-auth.d.ts.map +1 -0
  260. package/dist/server/request-auth.js +32 -0
  261. package/dist/server/request-auth.js.map +1 -0
  262. package/dist/server/types.d.ts +32 -0
  263. package/dist/server/types.d.ts.map +1 -1
  264. package/dist/server/types.js.map +1 -1
  265. package/dist/timers.d.ts +60 -0
  266. package/dist/timers.d.ts.map +1 -0
  267. package/dist/timers.js +33 -0
  268. package/dist/timers.js.map +1 -0
  269. package/dist/tracing/traceparent.d.ts +26 -0
  270. package/dist/tracing/traceparent.d.ts.map +1 -0
  271. package/dist/tracing/traceparent.js +53 -0
  272. package/dist/tracing/traceparent.js.map +1 -0
  273. package/package.json +11 -4
  274. package/src/adapters/http/client/transport.ts +31 -3
  275. package/src/adapters/http/client/types.ts +3 -2
  276. package/src/adapters/http/server/transport.ts +61 -26
  277. package/src/adapters/http/shared/headers.ts +7 -6
  278. package/src/adapters/local/client/transport.ts +74 -7
  279. package/src/adapters/local/client/types.ts +18 -0
  280. package/src/adapters/mock/client/transport.ts +9 -6
  281. package/src/adapters/mock/client/types.ts +7 -6
  282. package/src/adapters/port/transport.ts +124 -0
  283. package/src/adapters/websocket/client/index.ts +1 -0
  284. package/src/adapters/websocket/client/node.ts +34 -0
  285. package/src/adapters/websocket/client/transport.ts +251 -81
  286. package/src/adapters/websocket/client/types.ts +81 -21
  287. package/src/adapters/websocket/server/transport.ts +199 -301
  288. package/src/adapters/websocket/server/types.ts +20 -1
  289. package/src/adapters/websocket/shared/rpc.ts +453 -0
  290. package/src/browser.ts +51 -3
  291. package/src/client/call-types.ts +10 -14
  292. package/src/client/client.ts +28 -9
  293. package/src/client/deadline.ts +64 -0
  294. package/src/client/errors/README.md +2 -0
  295. package/src/client/errors/factory.ts +12 -8
  296. package/src/client/errors/http-errors.ts +5 -0
  297. package/src/client/errors/index.ts +1 -1
  298. package/src/client/errors/registry.ts +79 -22
  299. package/src/client/index.ts +21 -3
  300. package/src/client/middleware/cache.ts +120 -23
  301. package/src/client/middleware/circuit-breaker.ts +65 -35
  302. package/src/client/middleware/contexts.ts +17 -10
  303. package/src/client/middleware/items.ts +101 -6
  304. package/src/client/middleware/lru.ts +12 -0
  305. package/src/client/middleware/rate-limit.ts +9 -9
  306. package/src/client/middleware/resilience.ts +81 -0
  307. package/src/client/middleware/retry.ts +146 -34
  308. package/src/client/middleware/timeout.ts +57 -55
  309. package/src/client/middleware/tracing.ts +13 -4
  310. package/src/client/types.ts +9 -1
  311. package/src/clock.ts +21 -0
  312. package/src/duration.ts +56 -0
  313. package/src/index.ts +4 -0
  314. package/src/machines.ts +186 -0
  315. package/src/node.ts +11 -0
  316. package/src/procedures/capability.ts +7 -8
  317. package/src/procedures/collection/index.ts +9 -1
  318. package/src/procedures/collection/procedures.ts +57 -0
  319. package/src/procedures/collection/schemas.ts +110 -0
  320. package/src/procedures/collection/storage.ts +38 -0
  321. package/src/procedures/core/array.ts +79 -31
  322. package/src/procedures/core/index.ts +17 -2
  323. package/src/procedures/core/logic.ts +1 -1
  324. package/src/procedures/core/math.ts +5 -1
  325. package/src/procedures/core/meta.ts +45 -8
  326. package/src/procedures/core/object.ts +48 -14
  327. package/src/procedures/core/operands.ts +7 -0
  328. package/src/procedures/core/string.ts +4 -2
  329. package/src/procedures/core/type.ts +4 -2
  330. package/src/procedures/define-procedure.ts +73 -20
  331. package/src/procedures/discovery.ts +4 -6
  332. package/src/procedures/effects.ts +35 -0
  333. package/src/procedures/idempotency.ts +152 -0
  334. package/src/procedures/index.ts +18 -2
  335. package/src/procedures/interceptors.ts +28 -11
  336. package/src/procedures/invoke.ts +19 -5
  337. package/src/procedures/manifest.ts +158 -0
  338. package/src/procedures/ref.ts +4 -2
  339. package/src/procedures/runtime-programs.ts +27 -0
  340. package/src/procedures/types.ts +16 -0
  341. package/src/protocol.ts +108 -0
  342. package/src/server/host-policy.ts +8 -5
  343. package/src/server/host-procedures.ts +102 -0
  344. package/src/server/index.ts +5 -2
  345. package/src/server/procedure-server.ts +328 -12
  346. package/src/server/request-auth.ts +35 -0
  347. package/src/server/types.ts +37 -0
  348. package/src/timers.ts +82 -0
  349. package/src/tracing/traceparent.ts +61 -0
  350. package/dist/procedures/cli/announce.d.ts +0 -67
  351. package/dist/procedures/cli/announce.d.ts.map +0 -1
  352. package/dist/procedures/cli/announce.js +0 -392
  353. package/dist/procedures/cli/announce.js.map +0 -1
  354. package/dist/procedures/cli/discover.d.ts +0 -66
  355. package/dist/procedures/cli/discover.d.ts.map +0 -1
  356. package/dist/procedures/cli/discover.js +0 -310
  357. package/dist/procedures/cli/discover.js.map +0 -1
  358. package/dist/procedures/cli/index.d.ts +0 -13
  359. package/dist/procedures/cli/index.d.ts.map +0 -1
  360. package/dist/procedures/cli/index.js +0 -203
  361. package/dist/procedures/cli/index.js.map +0 -1
  362. package/dist/procedures/cli/init.d.ts +0 -17
  363. package/dist/procedures/cli/init.d.ts.map +0 -1
  364. package/dist/procedures/cli/init.js +0 -336
  365. package/dist/procedures/cli/init.js.map +0 -1
  366. package/src/procedures/cli/announce.ts +0 -470
  367. package/src/procedures/cli/discover.ts +0 -390
  368. package/src/procedures/cli/index.ts +0 -231
  369. package/src/procedures/cli/init.ts +0 -370
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The credentials of a network request (roadmap R18). A server transport reads them into
3
+ * `ServerRequest.credentials`, and leaves the secret headers out of the metadata, so a handler
4
+ * and a nested call do not see them. `ProcedureServer` examines them.
5
+ */
6
+ /** The headers that carry a secret. They do not go into the metadata of a request. */
7
+ const SECRET_HEADERS = new Set(["authorization", "proxy-authorization", "cookie", "x-api-key"]);
8
+ /** The headers without the secret ones, and without the headers that are not text. */
9
+ export function withoutSecretHeaders(headers) {
10
+ const out = {};
11
+ for (const [key, value] of Object.entries(headers)) {
12
+ if (!SECRET_HEADERS.has(key.toLowerCase()) && typeof value === "string")
13
+ out[key] = value;
14
+ }
15
+ return out;
16
+ }
17
+ /** The token of an `Authorization: Bearer <token>` header, or undefined. */
18
+ export function bearerOf(header) {
19
+ return typeof header === "string" && header.startsWith("Bearer ") ? header.slice("Bearer ".length) : undefined;
20
+ }
21
+ /**
22
+ * The credentials of a request or of a WebSocket upgrade: the bearer token of its
23
+ * `Authorization` header, or else of its `token` query (a browser WebSocket cannot set headers).
24
+ */
25
+ export function credentialsOf(request) {
26
+ const bearer = bearerOf(request.headers["authorization"]);
27
+ if (bearer !== undefined)
28
+ return { bearer };
29
+ const query = new URL(request.url ?? "/", "http://localhost").searchParams.get("token");
30
+ return query === null ? {} : { bearer: query };
31
+ }
32
+ //# sourceMappingURL=request-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-auth.js","sourceRoot":"","sources":["../../src/server/request-auth.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,sFAAsF;AACtF,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,eAAe,EAAE,qBAAqB,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;AAEhG,sFAAsF;AACtF,MAAM,UAAU,oBAAoB,CAAC,OAAgC;IACnE,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC5F,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,QAAQ,CAAC,MAAe;IACtC,OAAO,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACjH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,OAAuE;IACnG,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC;IAC1D,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAC5C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACxF,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AACjD,CAAC"}
@@ -21,6 +21,38 @@ export interface ServerRequest<TReq = unknown> {
21
21
  metadata: Metadata;
22
22
  /** Abort signal for cancellation */
23
23
  signal?: AbortSignal;
24
+ /**
25
+ * The credentials that a network transport read from the request: the bearer token of an
26
+ * `Authorization` header, or of the `token` query of a WebSocket connection (roadmap R18). They
27
+ * are not in the metadata, so a handler and a nested call do not see them. A request without
28
+ * credentials comes from this process (a direct `handle()`, MCP over stdio).
29
+ */
30
+ credentials?: Credentials | undefined;
31
+ /** The principal of the request: who sends it. `ProcedureServer` sets it when it authenticates the request. */
32
+ principal?: Principal | undefined;
33
+ }
34
+ /** The credentials of a request. */
35
+ export interface Credentials {
36
+ /** The bearer token that the request presents. */
37
+ readonly bearer?: string | undefined;
38
+ }
39
+ /** Who sends a request (roadmap R18). */
40
+ export interface Principal {
41
+ /** The id of the principal. With the token of a host: "token". */
42
+ readonly id: string;
43
+ /** How the server authenticated it: "token", or the name of an authenticate function. */
44
+ readonly via: string;
45
+ /** More facts about the principal, from an authenticate function. */
46
+ readonly claims?: Readonly<Record<string, unknown>> | undefined;
47
+ }
48
+ /**
49
+ * The contract of a server transport (roadmap R18): a transport turns each protocol request
50
+ * into a `ServerRequest` (with its signal and its credentials), gives it to `handle()`, and turns
51
+ * the `ServerResponse` back (a value, a stream or an error). `Server` and `ProcedureServer`
52
+ * satisfy it, and a test can give a function.
53
+ */
54
+ export interface RequestHandler {
55
+ handle(request: ServerRequest): Promise<ServerResponse>;
24
56
  }
25
57
  /**
26
58
  * Server response in unified RPC format.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAGnE,YAAY,EAAE,MAAM,EAAE,CAAC;AAEvB;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,IAAI,GAAG,OAAO;IAC3C,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IAEX,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IAEf,sBAAsB;IACtB,OAAO,EAAE,IAAI,CAAC;IAEd,qDAAqD;IACrD,QAAQ,EAAE,QAAQ,CAAC;IAEnB,oCAAoC;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc,CAAC,IAAI,GAAG,OAAO;IAC5C,mCAAmC;IACnC,EAAE,EAAE,MAAM,CAAC;IAEX,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IAEf,iDAAiD;IACjD,OAAO,CAAC,EAAE,IAAI,CAAC;IAEf;;;;OAIG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;IAE7B,wBAAwB;IACxB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,GAAG,OAAO,IAAI,CAC1D,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,KACzB,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;AAE1D;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,IAAI,GAAG,OAAO;IAC3C,2BAA2B;IAC3B,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;IAE7B,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,GAAG,OAAO,IAAI,CACzD,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,KACzB,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;AAEnC;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,GAAG,OAAO,IAAI,CAC7D,IAAI,EAAE,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,KAC3B,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAE9B;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;OAGG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtB;;OAEG;IACH,SAAS,IAAI,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,MAAM,EAAE,MAAM,EAOzB;CACF;AAED;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;aAGlB,IAAI,EAAE,MAAM;aACZ,SAAS,EAAE,OAAO;IAHpC,YACE,OAAO,EAAE,MAAM,EACC,IAAI,GAAE,MAAc,EACpB,SAAS,GAAE,OAAe,EAI3C;CACF"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAGnE,YAAY,EAAE,MAAM,EAAE,CAAC;AAEvB;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,IAAI,GAAG,OAAO;IAC3C,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IAEX,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;IAEf,sBAAsB;IACtB,OAAO,EAAE,IAAI,CAAC;IAEd,qDAAqD;IACrD,QAAQ,EAAE,QAAQ,CAAC;IAEnB,oCAAoC;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAEtC,+GAA+G;IAC/G,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CACnC;AAED,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC1B,kDAAkD;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAED,yCAAyC;AACzC,MAAM,WAAW,SAAS;IACxB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;CACjE;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACzD;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc,CAAC,IAAI,GAAG,OAAO;IAC5C,mCAAmC;IACnC,EAAE,EAAE,MAAM,CAAC;IAEX,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IAEf,iDAAiD;IACjD,OAAO,CAAC,EAAE,IAAI,CAAC;IAEf;;;;OAIG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;IAE7B,wBAAwB;IACxB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,GAAG,OAAO,IAAI,CAC1D,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,KACzB,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;AAE1D;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,IAAI,GAAG,OAAO;IAC3C,2BAA2B;IAC3B,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;IAE7B,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,GAAG,OAAO,IAAI,CACzD,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,KACzB,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;AAEnC;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,GAAG,OAAO,IAAI,CAC7D,IAAI,EAAE,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,KAC3B,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAE9B;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;OAGG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtB;;OAEG;IACH,SAAS,IAAI,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,MAAM,EAAE,MAAM,EAOzB;CACF;AAED;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;aAGlB,IAAI,EAAE,MAAM;aACZ,SAAS,EAAE,OAAO;IAHpC,YACE,OAAO,EAAE,MAAM,EACC,IAAI,GAAE,MAAc,EACpB,SAAS,GAAE,OAAe,EAI3C;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAmHH;;GAEG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,MAAc;QACxB,KAAK,CACH,wBAAwB,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,SAAS,GACxD,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAC7C,EAAE,CACH,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IAGlB,IAAI;IACJ,SAAS;IAH3B,YACE,OAAe,EACC,IAAI,GAAW,KAAK,EACpB,SAAS,GAAY,KAAK;QAE1C,KAAK,CAAC,OAAO,CAAC,CAAC;oBAHC,IAAI;yBACJ,SAAS;QAGzB,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwJH;;GAEG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,MAAc;QACxB,KAAK,CACH,wBAAwB,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,SAAS,GACxD,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAC7C,EAAE,CACH,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IAGlB,IAAI;IACJ,SAAS;IAH3B,YACE,OAAe,EACC,IAAI,GAAW,KAAK,EACpB,SAAS,GAAY,KAAK;QAE1C,KAAK,CAAC,OAAO,CAAC,CAAC;oBAHC,IAAI;yBACJ,SAAS;QAGzB,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * The timer settings of the core, as data (roadmap R34).
3
+ *
4
+ * Each default time of the middleware, the transports and the server comes from this object, so
5
+ * a tool can read the settings without a call. `@procedures/systems` binds them to the symbols of
6
+ * the timer law of `systems`, and examines rules such as "the time of one try is less than the
7
+ * request time of the WebSocket". The values are milliseconds. The options of an application
8
+ * are Durations (roadmap R11), and they replace these values.
9
+ */
10
+ /** The default times of the core, in milliseconds. */
11
+ export interface TimerDefaults {
12
+ readonly retry: {
13
+ /** The tries after the first one. */
14
+ readonly maxRetries: number;
15
+ readonly retryDelayMs: number;
16
+ readonly backoffMultiplier: number;
17
+ /** The longest backoff. Infinity: no limit. */
18
+ readonly maxDelayMs: number;
19
+ };
20
+ readonly circuitBreaker: {
21
+ readonly failureWindowMs: number;
22
+ readonly resetTimeoutMs: number;
23
+ };
24
+ readonly cache: {
25
+ readonly ttlMs: number;
26
+ readonly statsIntervalMs: number;
27
+ };
28
+ readonly rateLimit: {
29
+ readonly windowMs: number;
30
+ };
31
+ readonly webSocketClient: {
32
+ /** The time of the handshake. */
33
+ readonly connectionTimeoutMs: number;
34
+ /** The time until the first frame of a call. */
35
+ readonly requestTimeoutMs: number;
36
+ readonly heartbeatIntervalMs: number;
37
+ readonly heartbeatTimeoutMs: number;
38
+ /** The pongs that can go missing, one after the other, before the connection closes. */
39
+ readonly heartbeatMisses: number;
40
+ readonly reconnectInitialDelayMs: number;
41
+ readonly reconnectMaxDelayMs: number;
42
+ };
43
+ readonly webSocketServer: {
44
+ readonly heartbeatIntervalMs: number;
45
+ readonly heartbeatMisses: number;
46
+ /** The time until the first frame of a call of the server to a client. */
47
+ readonly reverseRequestTimeoutMs: number;
48
+ };
49
+ readonly idempotency: {
50
+ /** The time that the server keeps the result of a keyed write. */
51
+ readonly ttlMs: number;
52
+ };
53
+ readonly server: {
54
+ /** The time that `ProcedureServer.stop()` waits for the calls that run. */
55
+ readonly stopGraceMs: number;
56
+ };
57
+ }
58
+ /** The default times of the core. The middleware, the transports and the server read them. */
59
+ export declare const TIMER_DEFAULTS: TimerDefaults;
60
+ //# sourceMappingURL=timers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timers.d.ts","sourceRoot":"","sources":["../src/timers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,sDAAsD;AACtD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE;QACd,qCAAqC;QACrC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;QACnC,+CAA+C;QAC/C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF,QAAQ,CAAC,cAAc,EAAE;QACvB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;QACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;KACjC,CAAC;IACF,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;KAClC,CAAC;IACF,QAAQ,CAAC,SAAS,EAAE;QAClB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,QAAQ,CAAC,eAAe,EAAE;QACxB,iCAAiC;QACjC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;QACrC,gDAAgD;QAChD,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;QAClC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;QACrC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;QACpC,wFAAwF;QACxF,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;QACjC,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC;QACzC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;KACtC,CAAC;IACF,QAAQ,CAAC,eAAe,EAAE;QACxB,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;QACrC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;QACjC,0EAA0E;QAC1E,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC;KAC1C,CAAC;IACF,QAAQ,CAAC,WAAW,EAAE;QACpB,kEAAkE;QAClE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,QAAQ,CAAC,MAAM,EAAE;QACf,2EAA2E;QAC3E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;KAC9B,CAAC;CACH;AAED,8FAA8F;AAC9F,eAAO,MAAM,cAAc,EAAE,aAqB3B,CAAC"}
package/dist/timers.js ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The timer settings of the core, as data (roadmap R34).
3
+ *
4
+ * Each default time of the middleware, the transports and the server comes from this object, so
5
+ * a tool can read the settings without a call. `@procedures/systems` binds them to the symbols of
6
+ * the timer law of `systems`, and examines rules such as "the time of one try is less than the
7
+ * request time of the WebSocket". The values are milliseconds. The options of an application
8
+ * are Durations (roadmap R11), and they replace these values.
9
+ */
10
+ /** The default times of the core. The middleware, the transports and the server read them. */
11
+ export const TIMER_DEFAULTS = Object.freeze({
12
+ retry: Object.freeze({ maxRetries: 3, retryDelayMs: 1000, backoffMultiplier: 2, maxDelayMs: Number.POSITIVE_INFINITY }),
13
+ circuitBreaker: Object.freeze({ failureWindowMs: 10_000, resetTimeoutMs: 30_000 }),
14
+ cache: Object.freeze({ ttlMs: 60_000, statsIntervalMs: 60_000 }),
15
+ rateLimit: Object.freeze({ windowMs: 60_000 }),
16
+ webSocketClient: Object.freeze({
17
+ connectionTimeoutMs: 10_000,
18
+ requestTimeoutMs: 30_000,
19
+ // 20 s: with the pong timeout of 5 s, the client finds a dead connection after 25 s, before a
20
+ // call on it reaches the request time of 30 s. Before, 30 s gave 35 s (the timer law, R34).
21
+ heartbeatIntervalMs: 20_000,
22
+ heartbeatTimeoutMs: 5_000,
23
+ heartbeatMisses: 1,
24
+ reconnectInitialDelayMs: 1_000,
25
+ reconnectMaxDelayMs: 30_000,
26
+ }),
27
+ // 15 s: with 2 misses, the server finds a dead client after 30 s, not later than a call of the
28
+ // server to it reaches its request time of 30 s. Before, 30 s gave 60 s (the timer law, R34).
29
+ webSocketServer: Object.freeze({ heartbeatIntervalMs: 15_000, heartbeatMisses: 2, reverseRequestTimeoutMs: 30_000 }),
30
+ idempotency: Object.freeze({ ttlMs: 10 * 60_000 }),
31
+ server: Object.freeze({ stopGraceMs: 0 }),
32
+ });
33
+ //# sourceMappingURL=timers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timers.js","sourceRoot":"","sources":["../src/timers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAmDH,8FAA8F;AAC9F,MAAM,CAAC,MAAM,cAAc,GAAkB,MAAM,CAAC,MAAM,CAAC;IACzD,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,iBAAiB,EAAE,CAAC;IACvH,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,eAAe,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC;IAClF,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC;IAChE,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAC9C,eAAe,EAAE,MAAM,CAAC,MAAM,CAAC;QAC7B,mBAAmB,EAAE,MAAM;QAC3B,gBAAgB,EAAE,MAAM;QACxB,8FAA8F;QAC9F,4FAA4F;QAC5F,mBAAmB,EAAE,MAAM;QAC3B,kBAAkB,EAAE,KAAK;QACzB,eAAe,EAAE,CAAC;QAClB,uBAAuB,EAAE,KAAK;QAC9B,mBAAmB,EAAE,MAAM;KAC5B,CAAC;IACF,+FAA+F;IAC/F,8FAA8F;IAC9F,eAAe,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,mBAAmB,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,EAAE,uBAAuB,EAAE,MAAM,EAAE,CAAC;IACpH,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,GAAG,MAAM,EAAE,CAAC;IAClD,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC;CAC1C,CAAC,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The W3C trace context (roadmap R16): `traceparent` is `00-<trace id>-<span id>-<flags>`, with a
3
+ * trace id of 32 hex digits and a span id of 16. The tracing middleware of a client sends it in
4
+ * the metadata of a call (and HTTP as the `traceparent` header). The tracing interceptor of a
5
+ * server continues that trace, and gives it to the nested calls, so one trace goes from the
6
+ * client to the last handler. Before, the client and the server made two traces.
7
+ */
8
+ /** The metadata key of the W3C trace context of a call. */
9
+ export declare const TRACEPARENT_METADATA_KEY = "traceparent";
10
+ /** A trace context: the trace, the span of the caller, and the sampled flag. */
11
+ export interface TraceContext {
12
+ readonly traceId: string;
13
+ readonly spanId: string;
14
+ readonly sampled: boolean;
15
+ }
16
+ /** This function makes a new trace id: 32 random hex digits. */
17
+ export declare function newTraceId(): string;
18
+ /** This function makes a new span id: 16 random hex digits. */
19
+ export declare function newSpanId(): string;
20
+ /** True when the ids have the W3C form. */
21
+ export declare function isW3cIds(traceId: string, spanId: string): boolean;
22
+ /** The `traceparent` of a trace and a span. */
23
+ export declare function formatTraceparent(traceId: string, spanId: string, sampled?: boolean): string;
24
+ /** The trace context of a `traceparent` value, or undefined when it is not valid. */
25
+ export declare function parseTraceparent(value: unknown): TraceContext | undefined;
26
+ //# sourceMappingURL=traceparent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traceparent.d.ts","sourceRoot":"","sources":["../../src/tracing/traceparent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,2DAA2D;AAC3D,eAAO,MAAM,wBAAwB,gBAAgB,CAAC;AAMtD,gFAAgF;AAChF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAUD,gEAAgE;AAChE,wBAAgB,UAAU,IAAI,MAAM,CAGnC;AAED,+DAA+D;AAC/D,wBAAgB,SAAS,IAAI,MAAM,CAGlC;AAED,2CAA2C;AAC3C,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAEjE;AAED,+CAA+C;AAC/C,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,UAAO,GAAG,MAAM,CAEzF;AAED,qFAAqF;AACrF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAOzE"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The W3C trace context (roadmap R16): `traceparent` is `00-<trace id>-<span id>-<flags>`, with a
3
+ * trace id of 32 hex digits and a span id of 16. The tracing middleware of a client sends it in
4
+ * the metadata of a call (and HTTP as the `traceparent` header). The tracing interceptor of a
5
+ * server continues that trace, and gives it to the nested calls, so one trace goes from the
6
+ * client to the last handler. Before, the client and the server made two traces.
7
+ */
8
+ /** The metadata key of the W3C trace context of a call. */
9
+ export const TRACEPARENT_METADATA_KEY = "traceparent";
10
+ const TRACEPARENT = /^00-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/;
11
+ const ZERO_TRACE = "0".repeat(32);
12
+ const ZERO_SPAN = "0".repeat(16);
13
+ function randomHex(bytes) {
14
+ const values = new Uint8Array(bytes);
15
+ const crypto = globalThis.crypto;
16
+ if (crypto?.getRandomValues)
17
+ crypto.getRandomValues(values);
18
+ else
19
+ for (let index = 0; index < bytes; index++)
20
+ values[index] = Math.floor(Math.random() * 256);
21
+ return Array.from(values, (value) => value.toString(16).padStart(2, "0")).join("");
22
+ }
23
+ /** This function makes a new trace id: 32 random hex digits. */
24
+ export function newTraceId() {
25
+ const id = randomHex(16);
26
+ return id === ZERO_TRACE ? newTraceId() : id;
27
+ }
28
+ /** This function makes a new span id: 16 random hex digits. */
29
+ export function newSpanId() {
30
+ const id = randomHex(8);
31
+ return id === ZERO_SPAN ? newSpanId() : id;
32
+ }
33
+ /** True when the ids have the W3C form. */
34
+ export function isW3cIds(traceId, spanId) {
35
+ return /^[0-9a-f]{32}$/.test(traceId) && /^[0-9a-f]{16}$/.test(spanId) && traceId !== ZERO_TRACE && spanId !== ZERO_SPAN;
36
+ }
37
+ /** The `traceparent` of a trace and a span. */
38
+ export function formatTraceparent(traceId, spanId, sampled = true) {
39
+ return `00-${traceId}-${spanId}-${sampled ? "01" : "00"}`;
40
+ }
41
+ /** The trace context of a `traceparent` value, or undefined when it is not valid. */
42
+ export function parseTraceparent(value) {
43
+ if (typeof value !== "string")
44
+ return undefined;
45
+ const match = TRACEPARENT.exec(value.trim().toLowerCase());
46
+ if (!match)
47
+ return undefined;
48
+ const [, traceId, spanId, flags] = match;
49
+ if (traceId === ZERO_TRACE || spanId === ZERO_SPAN)
50
+ return undefined;
51
+ return { traceId: traceId, spanId: spanId, sampled: (parseInt(flags, 16) & 1) === 1 };
52
+ }
53
+ //# sourceMappingURL=traceparent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traceparent.js","sourceRoot":"","sources":["../../src/tracing/traceparent.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,2DAA2D;AAC3D,MAAM,CAAC,MAAM,wBAAwB,GAAG,aAAa,CAAC;AAEtD,MAAM,WAAW,GAAG,kDAAkD,CAAC;AACvE,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAClC,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AASjC,SAAS,SAAS,CAAC,KAAa;IAC9B,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;IACrC,MAAM,MAAM,GAAI,UAAmF,CAAC,MAAM,CAAC;IAC3G,IAAI,MAAM,EAAE,eAAe;QAAE,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;;QACvD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE,KAAK,EAAE;YAAE,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;IACjG,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACrF,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,UAAU;IACxB,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;IACzB,OAAO,EAAE,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/C,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,SAAS;IACvB,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IACxB,OAAO,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC7C,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,QAAQ,CAAC,OAAe,EAAE,MAAc;IACtD,OAAO,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,OAAO,KAAK,UAAU,IAAI,MAAM,KAAK,SAAS,CAAC;AAC3H,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,MAAc,EAAE,OAAO,GAAG,IAAI;IAC/E,OAAO,MAAM,OAAO,IAAI,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5D,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChD,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3D,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG,KAAK,CAAC;IACzC,IAAI,OAAO,KAAK,UAAU,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACrE,OAAO,EAAE,OAAO,EAAE,OAAQ,EAAE,MAAM,EAAE,MAAO,EAAE,OAAO,EAAE,CAAC,QAAQ,CAAC,KAAM,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;AAC3F,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@procedures/client",
4
- "version": "0.2.3",
4
+ "version": "0.4.0",
5
5
  "description": "Procedures as data for TypeScript: define typed procedures once and call them in process, over HTTP, WebSocket, the CLI or MCP. Streaming, middleware, retries, caching and a JSON program format.",
6
6
  "keywords": [
7
7
  "rpc",
@@ -43,6 +43,10 @@
43
43
  "types": "./dist/browser.d.ts",
44
44
  "import": "./dist/browser.js"
45
45
  },
46
+ "./node": {
47
+ "types": "./dist/node.d.ts",
48
+ "import": "./dist/node.js"
49
+ },
46
50
  "./register": {
47
51
  "types": "./dist/register.d.ts",
48
52
  "import": "./dist/register.js"
@@ -68,9 +72,6 @@
68
72
  "import": "./dist/server/index.js"
69
73
  }
70
74
  },
71
- "bin": {
72
- "client-registry": "./dist/procedures/cli/index.js"
73
- },
74
75
  "files": [
75
76
  "dist",
76
77
  "src",
@@ -90,14 +91,20 @@
90
91
  "provenance": true
91
92
  },
92
93
  "dependencies": {
94
+ "@mark1russell7/algebra": "^0.5.0",
95
+ "@mark1russell7/quantity": "^0.2.0",
96
+ "@mark1russell7/service": "^0.4.0",
93
97
  "ws": "^8.18.3",
94
98
  "zod": "^4.6.5"
95
99
  },
96
100
  "devDependencies": {
97
101
  "@mark1russell7/cue": "^1.0.0",
102
+ "@stryker-mutator/core": "10.0.0",
103
+ "@stryker-mutator/vitest-runner": "10.0.0",
98
104
  "@types/express": "^5.0.0",
99
105
  "@types/node": "^22.0.0",
100
106
  "@types/ws": "^8.18.1",
107
+ "fast-check": "^4.10.2",
101
108
  "typescript": "^7.0.2",
102
109
  "vitest": "^5.0.3"
103
110
  },
@@ -12,6 +12,21 @@ import type {
12
12
  } from "../../../client/types.js";
13
13
 
14
14
  import type { HttpTransportOptions } from "./types.js";
15
+ import { DELIVERY_METADATA_KEY, RETRY_AFTER_METADATA_KEY, isNotSentError } from "../../../client/middleware/items.js";
16
+
17
+ /**
18
+ * The wait that an error response asks for, in milliseconds: `retryAfterMs` of the body of the
19
+ * server transport, or else the Retry-After header (seconds, or an HTTP date).
20
+ */
21
+ function retryAfterMsOf(header: string | null, body: unknown): number | undefined {
22
+ const fromBody = (body as { retryAfterMs?: unknown } | null | undefined)?.retryAfterMs;
23
+ if (typeof fromBody === "number" && Number.isFinite(fromBody) && fromBody >= 0) return fromBody;
24
+ if (header === null || header.trim() === "") return undefined;
25
+ const seconds = Number(header);
26
+ if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1000;
27
+ const date = Date.parse(header);
28
+ return Number.isNaN(date) ? undefined : Math.max(0, date - Date.now());
29
+ }
15
30
 
16
31
  /** The media type of a stream response: one JSON value on each line. */
17
32
  const NDJSON = "application/x-ndjson";
@@ -32,6 +47,8 @@ import {
32
47
  createAbortError,
33
48
  createErrorFromException,
34
49
  } from "../shared/index.js";
50
+ import { optionalMs } from "../../../duration.js";
51
+ import { PROTOCOL_HEADER, PROTOCOL_VERSION } from "../../../protocol.js";
35
52
 
36
53
  /**
37
54
  * HTTP Client Transport
@@ -74,7 +91,7 @@ export class HttpTransport implements Transport {
74
91
  this.headerConverter =
75
92
  options.headerConverter || createDefaultHeaderConverter();
76
93
  this.defaultHeaders = options.defaultHeaders || {};
77
- this.timeout = options.timeout;
94
+ this.timeout = optionalMs(options.timeout, "timeout");
78
95
  }
79
96
 
80
97
  /**
@@ -123,6 +140,8 @@ export class HttpTransport implements Transport {
123
140
  [HTTPHeaders.CONTENT_TYPE]: "application/json",
124
141
  // A streaming procedure answers with NDJSON; other procedures with JSON
125
142
  Accept: `${NDJSON}, application/json`,
143
+ // The protocol version of this client (roadmap R25)
144
+ [PROTOCOL_HEADER]: String(PROTOCOL_VERSION),
126
145
  ...this.defaultHeaders,
127
146
  ...metadataHeaders,
128
147
  },
@@ -153,6 +172,13 @@ export class HttpTransport implements Transport {
153
172
  // the client kept only the HTTP status ("HTTP 500").
154
173
  const status = this.httpStatusToUniversal(response.status as HTTPStatus, responseBody);
155
174
  finished = true;
175
+ if (status.type === "error") {
176
+ const retryAfter = retryAfterMsOf(response.headers.get("Retry-After"), responseBody);
177
+ if (retryAfter !== undefined) metadata[RETRY_AFTER_METADATA_KEY] = retryAfter;
178
+ // The reason of a FORBIDDEN error (roadmap R25)
179
+ const reason = (responseBody as { reason?: unknown } | null | undefined)?.reason;
180
+ if (typeof reason === "string") metadata["reason"] = reason;
181
+ }
156
182
 
157
183
  // Yield single response item
158
184
  yield {
@@ -183,7 +209,9 @@ export class HttpTransport implements Transport {
183
209
  retryable: errorDetails.retryable,
184
210
  },
185
211
  payload: null as TRes,
186
- metadata: {},
212
+ // A refused connection sent nothing. After a reset or a timeout, the server can have
213
+ // the request, so only an idempotent call can go again (R1).
214
+ metadata: { [DELIVERY_METADATA_KEY]: isNotSentError(error) ? "not-sent" : "indeterminate" },
187
215
  };
188
216
  } finally {
189
217
  if (timeoutId) clearTimeout(timeoutId);
@@ -251,7 +279,7 @@ export class HttpTransport implements Transport {
251
279
  id,
252
280
  status: { type: "error", code: "STREAM_ENDED", message: "The stream ended without its end line", retryable: true },
253
281
  payload: null as TRes,
254
- metadata,
282
+ metadata: { ...metadata, [DELIVERY_METADATA_KEY]: "indeterminate" },
255
283
  };
256
284
  } finally {
257
285
  reader.releaseLock();
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  import type { UrlStrategy, HttpMethodStrategy, HeaderConverter } from "../shared/index.js";
9
+ import type { Duration } from "../../../duration.js";
9
10
 
10
11
  /**
11
12
  * HTTP Client Transport Configuration
@@ -28,6 +29,6 @@ export interface HttpTransportOptions {
28
29
  /** Default headers applied to all requests */
29
30
  defaultHeaders?: Record<string, string>;
30
31
 
31
- /** Timeout for fetch requests (milliseconds) */
32
- timeout?: number;
32
+ /** The time to the first item of a response, for example `seconds(30)` */
33
+ timeout?: Duration;
33
34
  }
@@ -10,16 +10,23 @@ import { createServer } from "http";
10
10
  import type { Server as HttpServer } from "http";
11
11
  import type { ServerTransport, ServerRequest, ServerResponse } from "../../../server/types.js";
12
12
  import type { Metadata } from "../../../client/types.js";
13
- import type { Server } from "../../../server/index.js";
13
+ import type { RequestHandler } from "../../../server/types.js";
14
14
  import { HTTPMethod, HTTPHeaders, decodeMetadataHeader, METADATA_HEADER_LIMIT } from "../shared/index.js";
15
15
  import { ERROR_REGISTRY } from "../../../client/errors/index.js";
16
16
  import type { HttpServerTransportOptions } from "./types.js";
17
17
  import { createPatternServerUrlStrategy } from "./strategies.js";
18
18
  import { checkBrowserRequest, type BrowserGuardOptions } from "../../../server/browser-guard.js";
19
+ import { bearerOf, withoutSecretHeaders } from "../../../server/request-auth.js";
20
+ import { PROTOCOL_HEADER, PROTOCOL_VERSION, errorCodeOf, httpStatusOf, protocolVersionOf } from "../../../protocol.js";
19
21
 
20
22
  /** The media type of a stream response: one JSON value on each line. */
21
23
  const NDJSON = "application/x-ndjson";
22
24
 
25
+ /** True when a stream response can run without an end (`STREAM_METADATA_KEY` of procedure-server.ts). */
26
+ function isUnboundedStream(response: { metadata?: Record<string, unknown> | undefined }): boolean {
27
+ return response.metadata?.["stream"] === "unbounded";
28
+ }
29
+
23
30
  /** The metadata keys that the transport sets: a query parameter or a header cannot replace them. */
24
31
  const RESERVED_METADATA = new Set(["headers", "query", "params"]);
25
32
 
@@ -35,10 +42,9 @@ class BodyError extends Error {
35
42
 
36
43
  /** The code and message of a thrown error, with its retryable flag (deep dive TRN-7). */
37
44
  function errorOf(error: unknown): { code: string; message: string; retryable: boolean } {
38
- const code = (error as { code?: unknown } | undefined)?.code;
39
45
  const retryable = (error as { retryable?: unknown } | undefined)?.retryable;
40
46
  return {
41
- code: typeof code === "string" ? code : "HANDLER_ERROR",
47
+ code: errorCodeOf(error),
42
48
  message: error instanceof Error ? error.message : String(error),
43
49
  retryable: typeof retryable === "boolean" ? retryable : false,
44
50
  };
@@ -64,24 +70,6 @@ function write(res: Response, chunk: string, signal: AbortSignal): Promise<void>
64
70
  });
65
71
  }
66
72
 
67
- /**
68
- * The HTTP status of the error codes of a procedure invocation (they are not in the error
69
- * registry, so before, a validation error was a 500).
70
- */
71
- const INVOCATION_HTTP_STATUS: Record<string, number> = {
72
- VALIDATION_ERROR: 400,
73
- NOT_EXPOSED: 403,
74
- NOT_DECLARED: 403,
75
- FORBIDDEN: 403,
76
- NOT_FOUND: 404,
77
- NO_HANDLER: 404,
78
- ABORTED: 499,
79
- TIMEOUT: 504,
80
- OUTPUT_VALIDATION_ERROR: 500,
81
- NO_OUTPUT: 500,
82
- HANDLER_ERROR: 500,
83
- };
84
-
85
73
  /**
86
74
  * HTTP server transport adapter for Express.
87
75
  *
@@ -126,7 +114,7 @@ export class HttpServerTransport implements ServerTransport {
126
114
  corsOptions: HttpServerTransportOptions["corsOptions"] | undefined;
127
115
  httpServer: HttpServer | undefined;
128
116
  };
129
- private server: Server;
117
+ private server: RequestHandler;
130
118
  /** The controllers of the requests in progress: stop() aborts them (deep dive TRN-15) */
131
119
  private openRequests = new Set<AbortController>();
132
120
  private stopped = false;
@@ -134,7 +122,7 @@ export class HttpServerTransport implements ServerTransport {
134
122
  /** The browser checks of each procedure call (see `server/browser-guard.ts`) */
135
123
  private readonly guard: BrowserGuardOptions;
136
124
 
137
- constructor(server: Server, options: HttpServerTransportOptions = {}) {
125
+ constructor(server: RequestHandler, options: HttpServerTransportOptions = {}) {
138
126
  this.server = server;
139
127
  const basePath = options.basePath ?? "/api";
140
128
  this.options = {
@@ -198,7 +186,8 @@ export class HttpServerTransport implements ServerTransport {
198
186
  HTTPHeaders.TRACE_ID,
199
187
  HTTPHeaders.SPAN_ID,
200
188
  HTTPHeaders.PARENT_SPAN_ID,
201
- HTTPHeaders.TIMEOUT,
189
+ "traceparent",
190
+ PROTOCOL_HEADER,
202
191
  HTTPHeaders.METADATA,
203
192
  "collection",
204
193
  "collectionName",
@@ -256,6 +245,18 @@ export class HttpServerTransport implements ServerTransport {
256
245
  * Converts to unified RPC format, processes, and sends response.
257
246
  */
258
247
  private async handleHttpRequest(req: Request, res: Response): Promise<void> {
248
+ // The protocol version of this server, on each response (roadmap R25)
249
+ res.setHeader(PROTOCOL_HEADER, String(PROTOCOL_VERSION));
250
+ const version = protocolVersionOf(req.headers[PROTOCOL_HEADER.toLowerCase()]);
251
+ if (version !== undefined && version > PROTOCOL_VERSION) {
252
+ res.status(400).json({
253
+ error: `This server speaks the protocol ${PROTOCOL_VERSION}, and the request uses ${version}`,
254
+ code: "PROTOCOL_VERSION",
255
+ retryable: false,
256
+ protocol: PROTOCOL_VERSION,
257
+ });
258
+ return;
259
+ }
259
260
  if (this.stopped) {
260
261
  res.status(503).json({ error: "Server stopped", code: "SERVER_STOPPED", retryable: true });
261
262
  return;
@@ -360,6 +361,26 @@ export class HttpServerTransport implements ServerTransport {
360
361
  ): Promise<void> {
361
362
  const ndjson = String(req.headers.accept ?? "").includes(NDJSON);
362
363
 
364
+ if (!ndjson && isUnboundedStream(response)) {
365
+ // The last item of a stream without an end never comes: refuse the call, and end the stream
366
+ // (roadmap R15: before, the request waited until a timeout)
367
+ void Promise.resolve(stream[Symbol.asyncIterator]().return?.()).catch(() => undefined);
368
+ this.serverResponseToHttp(
369
+ {
370
+ id: response.id,
371
+ status: {
372
+ type: "error",
373
+ code: "NOT_ACCEPTABLE",
374
+ message: `This procedure gives a stream that can run without an end. Send "Accept: ${NDJSON}" to read its items.`,
375
+ retryable: false,
376
+ },
377
+ metadata: {},
378
+ },
379
+ res
380
+ );
381
+ return;
382
+ }
383
+
363
384
  if (!ndjson) {
364
385
  let last: { value: unknown } | undefined;
365
386
  try {
@@ -424,11 +445,14 @@ export class HttpServerTransport implements ServerTransport {
424
445
  const id =
425
446
  (req.headers["x-request-id"] as string) ??
426
447
  `req-${Date.now()}-${Math.random()}`;
448
+ const bearer = bearerOf(req.headers["authorization"]);
427
449
 
428
450
  // Build metadata from headers and query params. The flattened query parameters cannot
429
451
  // replace headers, query or params (before, "?headers=x" replaced metadata.headers).
452
+ // The headers without the secrets: the credentials go in request.credentials, not in the
453
+ // metadata, so a handler and a nested call do not see them (roadmap R18)
430
454
  const metadata: Metadata = {
431
- headers: req.headers as Record<string, string>,
455
+ headers: withoutSecretHeaders(req.headers as Record<string, string>),
432
456
  query: req.query,
433
457
  params: req.params,
434
458
  };
@@ -505,6 +529,8 @@ export class HttpServerTransport implements ServerTransport {
505
529
  method,
506
530
  payload,
507
531
  metadata,
532
+ // A network request: ProcedureServer examines the token (roadmap R18)
533
+ credentials: bearer === undefined ? {} : { bearer },
508
534
  };
509
535
  }
510
536
 
@@ -524,7 +550,7 @@ export class HttpServerTransport implements ServerTransport {
524
550
  // HTTP status via the error registry rather than parseInt (which yields NaN -> 500, so every
525
551
  // error became a 500). See documentation/BUGS-2026-07.md (M7).
526
552
  const mapped =
527
- INVOCATION_HTTP_STATUS[status.code] ??
553
+ httpStatusOf(status.code) ??
528
554
  (ERROR_REGISTRY as Record<string, { httpStatus?: number }>)[status.code]?.httpStatus;
529
555
  httpStatusCode = mapped ?? (status.type === "success" ? 200 : 500);
530
556
  } else if (typeof status.code === "number") {
@@ -551,10 +577,19 @@ export class HttpServerTransport implements ServerTransport {
551
577
  }
552
578
  res.json(payload);
553
579
  } else {
580
+ // The wait that the error asks for: a Retry-After header in seconds, and the exact
581
+ // milliseconds in the body (R12)
582
+ const retryAfterMs = metadata["retry-after"];
583
+ const hasRetryAfter = typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs) && retryAfterMs >= 0;
584
+ if (hasRetryAfter) res.setHeader("Retry-After", String(Math.ceil(retryAfterMs / 1000)));
585
+ // The reason of a FORBIDDEN error travels on each face (roadmap R25)
586
+ const reason = typeof metadata["reason"] === "string" ? metadata["reason"] : undefined;
554
587
  res.json({
555
588
  error: status.message,
556
589
  code: status.code,
557
590
  retryable: status.retryable,
591
+ ...(hasRetryAfter ? { retryAfterMs } : {}),
592
+ ...(reason !== undefined ? { reason } : {}),
558
593
  });
559
594
  }
560
595
  }