rivetkit 2.0.2 → 2.0.4-rc.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 (403) hide show
  1. package/README.md +3 -5
  2. package/dist/browser/client.d.ts +2485 -0
  3. package/dist/browser/client.js +5182 -0
  4. package/dist/browser/client.js.map +1 -0
  5. package/dist/browser/inspector/client.d.ts +130 -0
  6. package/dist/browser/inspector/client.js +2854 -0
  7. package/dist/browser/inspector/client.js.map +1 -0
  8. package/dist/browser/v3-DnYObHH3.d.ts +279 -0
  9. package/dist/inspector.tar.gz +0 -0
  10. package/dist/schemas/actor-inspector/v1.ts +784 -0
  11. package/dist/schemas/actor-inspector/v2.ts +796 -0
  12. package/dist/schemas/actor-inspector/v3.ts +899 -0
  13. package/dist/schemas/actor-persist/v1.ts +225 -0
  14. package/dist/schemas/actor-persist/v2.ts +268 -0
  15. package/dist/schemas/actor-persist/v3.ts +280 -0
  16. package/dist/schemas/actor-persist/v4.ts +406 -0
  17. package/dist/schemas/client-protocol/v1.ts +441 -0
  18. package/dist/schemas/client-protocol/v2.ts +438 -0
  19. package/dist/schemas/client-protocol/v3.ts +554 -0
  20. package/dist/schemas/file-system-driver/v1.ts +108 -0
  21. package/dist/schemas/file-system-driver/v2.ts +142 -0
  22. package/dist/schemas/file-system-driver/v3.ts +167 -0
  23. package/dist/schemas/persist/v1.ts +781 -0
  24. package/dist/schemas/transport/v1.ts +697 -0
  25. package/dist/tsup/actor/errors.cjs +106 -0
  26. package/dist/tsup/actor/errors.cjs.map +1 -0
  27. package/dist/tsup/actor/errors.d.cts +188 -0
  28. package/dist/tsup/actor/errors.d.ts +188 -0
  29. package/dist/tsup/actor/errors.js +106 -0
  30. package/dist/tsup/actor/errors.js.map +1 -0
  31. package/dist/tsup/actor-router-consts-D29T1Z-K.d.cts +24 -0
  32. package/dist/tsup/actor-router-consts-D29T1Z-K.d.ts +24 -0
  33. package/dist/tsup/chunk-325TLXJT.js +1060 -0
  34. package/dist/tsup/chunk-325TLXJT.js.map +1 -0
  35. package/dist/tsup/chunk-424PT5DM.js +23 -0
  36. package/dist/tsup/chunk-424PT5DM.js.map +1 -0
  37. package/dist/tsup/chunk-4JVIG3SS.cjs +6289 -0
  38. package/dist/tsup/chunk-4JVIG3SS.cjs.map +1 -0
  39. package/dist/tsup/chunk-6LJAZ5R4.cjs +96 -0
  40. package/dist/tsup/chunk-6LJAZ5R4.cjs.map +1 -0
  41. package/dist/tsup/chunk-6XU3FMCB.cjs +534 -0
  42. package/dist/tsup/chunk-6XU3FMCB.cjs.map +1 -0
  43. package/dist/tsup/chunk-7HTNH26M.js +509 -0
  44. package/dist/tsup/chunk-7HTNH26M.js.map +1 -0
  45. package/dist/tsup/chunk-AUVH72RE.cjs +5977 -0
  46. package/dist/tsup/chunk-AUVH72RE.cjs.map +1 -0
  47. package/dist/tsup/chunk-D4BYUPNQ.js +645 -0
  48. package/dist/tsup/chunk-D4BYUPNQ.js.map +1 -0
  49. package/dist/tsup/chunk-HDQ2JUQT.cjs +23 -0
  50. package/dist/tsup/chunk-HDQ2JUQT.cjs.map +1 -0
  51. package/dist/tsup/chunk-HHXX2VRM.js +6289 -0
  52. package/dist/tsup/chunk-HHXX2VRM.js.map +1 -0
  53. package/dist/tsup/chunk-JEAEA2PB.js +49 -0
  54. package/dist/tsup/chunk-JEAEA2PB.js.map +1 -0
  55. package/dist/tsup/chunk-JYSEG3VF.cjs +642 -0
  56. package/dist/tsup/chunk-JYSEG3VF.cjs.map +1 -0
  57. package/dist/tsup/chunk-K6DGYILQ.js +2657 -0
  58. package/dist/tsup/chunk-K6DGYILQ.js.map +1 -0
  59. package/dist/tsup/chunk-KJSYAUOM.js +96 -0
  60. package/dist/tsup/chunk-KJSYAUOM.js.map +1 -0
  61. package/dist/tsup/chunk-L47L3ZWJ.cjs +509 -0
  62. package/dist/tsup/chunk-L47L3ZWJ.cjs.map +1 -0
  63. package/dist/tsup/chunk-LXUQ667X.js +2006 -0
  64. package/dist/tsup/chunk-LXUQ667X.js.map +1 -0
  65. package/dist/tsup/chunk-MXNPAB5W.js +5977 -0
  66. package/dist/tsup/chunk-MXNPAB5W.js.map +1 -0
  67. package/dist/tsup/chunk-N4KRDJ56.js +72 -0
  68. package/dist/tsup/chunk-N4KRDJ56.js.map +1 -0
  69. package/dist/tsup/chunk-NIYZDWMW.cjs +2006 -0
  70. package/dist/tsup/chunk-NIYZDWMW.cjs.map +1 -0
  71. package/dist/tsup/chunk-PQZHDKRW.cjs +1060 -0
  72. package/dist/tsup/chunk-PQZHDKRW.cjs.map +1 -0
  73. package/dist/tsup/chunk-PVOE6BU7.cjs +1050 -0
  74. package/dist/tsup/chunk-PVOE6BU7.cjs.map +1 -0
  75. package/dist/tsup/chunk-Q4UD2GA4.cjs +1810 -0
  76. package/dist/tsup/chunk-Q4UD2GA4.cjs.map +1 -0
  77. package/dist/tsup/chunk-QUD664YZ.js +1810 -0
  78. package/dist/tsup/chunk-QUD664YZ.js.map +1 -0
  79. package/dist/tsup/chunk-RTOCTWME.js +1050 -0
  80. package/dist/tsup/chunk-RTOCTWME.js.map +1 -0
  81. package/dist/tsup/chunk-SAZZ4SB2.cjs +2657 -0
  82. package/dist/tsup/chunk-SAZZ4SB2.cjs.map +1 -0
  83. package/dist/tsup/chunk-SR3KQE7Q.cjs +72 -0
  84. package/dist/tsup/chunk-SR3KQE7Q.cjs.map +1 -0
  85. package/dist/tsup/chunk-V2GHLYC6.cjs +49 -0
  86. package/dist/tsup/chunk-V2GHLYC6.cjs.map +1 -0
  87. package/dist/tsup/chunk-V3WG7XTW.cjs +645 -0
  88. package/dist/tsup/chunk-V3WG7XTW.cjs.map +1 -0
  89. package/dist/tsup/chunk-VKVNIQRQ.js +257 -0
  90. package/dist/tsup/chunk-VKVNIQRQ.js.map +1 -0
  91. package/dist/tsup/chunk-WMPW7JYC.js +642 -0
  92. package/dist/tsup/chunk-WMPW7JYC.js.map +1 -0
  93. package/dist/tsup/chunk-Z7HNQ2WF.js +534 -0
  94. package/dist/tsup/chunk-Z7HNQ2WF.js.map +1 -0
  95. package/dist/tsup/chunk-ZFY5J2EP.cjs +257 -0
  96. package/dist/tsup/chunk-ZFY5J2EP.cjs.map +1 -0
  97. package/dist/tsup/client/mod.cjs +33 -0
  98. package/dist/tsup/client/mod.cjs.map +1 -0
  99. package/dist/tsup/client/mod.d.cts +64 -0
  100. package/dist/tsup/client/mod.d.ts +64 -0
  101. package/dist/tsup/client/mod.js +33 -0
  102. package/dist/tsup/client/mod.js.map +1 -0
  103. package/dist/tsup/common/log.cjs +21 -0
  104. package/dist/tsup/common/log.cjs.map +1 -0
  105. package/dist/tsup/common/log.d.cts +34 -0
  106. package/dist/tsup/common/log.d.ts +34 -0
  107. package/dist/tsup/common/log.js +21 -0
  108. package/dist/tsup/common/log.js.map +1 -0
  109. package/dist/tsup/common/websocket.cjs +10 -0
  110. package/dist/tsup/common/websocket.cjs.map +1 -0
  111. package/dist/tsup/common/websocket.d.cts +3 -0
  112. package/dist/tsup/common/websocket.d.ts +3 -0
  113. package/dist/tsup/common/websocket.js +10 -0
  114. package/dist/tsup/common/websocket.js.map +1 -0
  115. package/dist/tsup/config-BiNoIHRs.d.cts +80 -0
  116. package/dist/tsup/config-BiNoIHRs.d.ts +80 -0
  117. package/dist/tsup/config-P3XujgRr.d.ts +2594 -0
  118. package/dist/tsup/config-_gfywqqI.d.cts +2594 -0
  119. package/dist/tsup/context-Bxd8Cx4H.d.cts +75 -0
  120. package/dist/tsup/context-uNA4TRn3.d.ts +75 -0
  121. package/dist/tsup/db/drizzle/mod.cjs +49 -0
  122. package/dist/tsup/db/drizzle/mod.cjs.map +1 -0
  123. package/dist/tsup/db/drizzle/mod.d.cts +17 -0
  124. package/dist/tsup/db/drizzle/mod.d.ts +17 -0
  125. package/dist/tsup/db/drizzle/mod.js +49 -0
  126. package/dist/tsup/db/drizzle/mod.js.map +1 -0
  127. package/dist/tsup/db/mod.cjs +9 -0
  128. package/dist/tsup/db/mod.cjs.map +1 -0
  129. package/dist/tsup/db/mod.d.cts +9 -0
  130. package/dist/tsup/db/mod.d.ts +9 -0
  131. package/dist/tsup/db/mod.js +9 -0
  132. package/dist/tsup/db/mod.js.map +1 -0
  133. package/dist/tsup/driver-BcLvZcKl.d.cts +13 -0
  134. package/dist/tsup/driver-CPGHKXyh.d.ts +13 -0
  135. package/dist/tsup/driver-helpers/mod.cjs +53 -0
  136. package/dist/tsup/driver-helpers/mod.cjs.map +1 -0
  137. package/dist/tsup/driver-helpers/mod.d.cts +47 -0
  138. package/dist/tsup/driver-helpers/mod.d.ts +47 -0
  139. package/dist/tsup/driver-helpers/mod.js +53 -0
  140. package/dist/tsup/driver-helpers/mod.js.map +1 -0
  141. package/dist/tsup/driver-test-suite/mod.cjs +4974 -0
  142. package/dist/tsup/driver-test-suite/mod.cjs.map +1 -0
  143. package/dist/tsup/driver-test-suite/mod.d.cts +73 -0
  144. package/dist/tsup/driver-test-suite/mod.d.ts +73 -0
  145. package/dist/tsup/driver-test-suite/mod.js +4974 -0
  146. package/dist/tsup/driver-test-suite/mod.js.map +1 -0
  147. package/dist/tsup/inspector/mod.cjs +164 -0
  148. package/dist/tsup/inspector/mod.cjs.map +1 -0
  149. package/dist/tsup/inspector/mod.d.cts +130 -0
  150. package/dist/tsup/inspector/mod.d.ts +130 -0
  151. package/dist/tsup/inspector/mod.js +164 -0
  152. package/dist/tsup/inspector/mod.js.map +1 -0
  153. package/dist/tsup/keys-CydblqMh.d.cts +13 -0
  154. package/dist/tsup/keys-CydblqMh.d.ts +13 -0
  155. package/dist/tsup/mod.cjs +82 -0
  156. package/dist/tsup/mod.cjs.map +1 -0
  157. package/dist/tsup/mod.d.cts +126 -0
  158. package/dist/tsup/mod.d.ts +126 -0
  159. package/dist/tsup/mod.js +82 -0
  160. package/dist/tsup/mod.js.map +1 -0
  161. package/dist/tsup/serve-test-suite/mod.cjs +2601 -0
  162. package/dist/tsup/serve-test-suite/mod.cjs.map +1 -0
  163. package/dist/tsup/serve-test-suite/mod.d.cts +9 -0
  164. package/dist/tsup/serve-test-suite/mod.d.ts +9 -0
  165. package/dist/tsup/serve-test-suite/mod.js +2601 -0
  166. package/dist/tsup/serve-test-suite/mod.js.map +1 -0
  167. package/dist/tsup/test/mod.cjs +90 -0
  168. package/dist/tsup/test/mod.cjs.map +1 -0
  169. package/dist/tsup/test/mod.d.cts +26 -0
  170. package/dist/tsup/test/mod.d.ts +26 -0
  171. package/dist/tsup/test/mod.js +90 -0
  172. package/dist/tsup/test/mod.js.map +1 -0
  173. package/dist/tsup/utils-fwx3o3K9.d.cts +18 -0
  174. package/dist/tsup/utils-fwx3o3K9.d.ts +18 -0
  175. package/dist/tsup/utils.cjs +43 -0
  176. package/dist/tsup/utils.cjs.map +1 -0
  177. package/dist/tsup/utils.d.cts +148 -0
  178. package/dist/tsup/utils.d.ts +148 -0
  179. package/dist/tsup/utils.js +43 -0
  180. package/dist/tsup/utils.js.map +1 -0
  181. package/dist/tsup/v3-DnYObHH3.d.cts +279 -0
  182. package/dist/tsup/v3-DnYObHH3.d.ts +279 -0
  183. package/dist/tsup/workflow/mod.cjs +16 -0
  184. package/dist/tsup/workflow/mod.cjs.map +1 -0
  185. package/dist/tsup/workflow/mod.d.cts +25 -0
  186. package/dist/tsup/workflow/mod.d.ts +25 -0
  187. package/dist/tsup/workflow/mod.js +16 -0
  188. package/dist/tsup/workflow/mod.js.map +1 -0
  189. package/package.json +293 -5
  190. package/src/actor/config.ts +1221 -0
  191. package/src/actor/conn/driver.ts +61 -0
  192. package/src/actor/conn/drivers/http.ts +17 -0
  193. package/src/actor/conn/drivers/raw-request.ts +24 -0
  194. package/src/actor/conn/drivers/raw-websocket.ts +65 -0
  195. package/src/actor/conn/drivers/websocket.ts +144 -0
  196. package/src/actor/conn/mod.ts +288 -0
  197. package/src/actor/conn/persisted.ts +81 -0
  198. package/src/actor/conn/state-manager.ts +196 -0
  199. package/src/actor/contexts/action.ts +47 -0
  200. package/src/actor/contexts/base/actor.ts +347 -0
  201. package/src/actor/contexts/base/conn-init.ts +68 -0
  202. package/src/actor/contexts/base/conn.ts +73 -0
  203. package/src/actor/contexts/before-action-response.ts +42 -0
  204. package/src/actor/contexts/before-connect.ts +31 -0
  205. package/src/actor/contexts/connect.ts +42 -0
  206. package/src/actor/contexts/create-conn-state.ts +32 -0
  207. package/src/actor/contexts/create-vars.ts +39 -0
  208. package/src/actor/contexts/create.ts +39 -0
  209. package/src/actor/contexts/destroy.ts +42 -0
  210. package/src/actor/contexts/disconnect.ts +43 -0
  211. package/src/actor/contexts/index.ts +33 -0
  212. package/src/actor/contexts/request.ts +80 -0
  213. package/src/actor/contexts/run.ts +47 -0
  214. package/src/actor/contexts/sleep.ts +42 -0
  215. package/src/actor/contexts/state-change.ts +42 -0
  216. package/src/actor/contexts/wake.ts +42 -0
  217. package/src/actor/contexts/websocket.ts +80 -0
  218. package/src/actor/database.ts +13 -0
  219. package/src/actor/definition.ts +64 -0
  220. package/src/actor/driver.ts +114 -0
  221. package/src/actor/errors.ts +556 -0
  222. package/src/actor/instance/connection-manager.ts +574 -0
  223. package/src/actor/instance/event-manager.ts +314 -0
  224. package/src/actor/instance/keys.ts +146 -0
  225. package/src/actor/instance/kv.ts +241 -0
  226. package/src/actor/instance/mod.ts +1658 -0
  227. package/src/actor/instance/persisted.ts +67 -0
  228. package/src/actor/instance/queue-manager.ts +603 -0
  229. package/src/actor/instance/queue.ts +345 -0
  230. package/src/actor/instance/schedule-manager.ts +392 -0
  231. package/src/actor/instance/state-manager.ts +542 -0
  232. package/src/actor/instance/traces-driver.ts +128 -0
  233. package/src/actor/keys.test.ts +275 -0
  234. package/src/actor/keys.ts +89 -0
  235. package/src/actor/log.ts +6 -0
  236. package/src/actor/mod.ts +110 -0
  237. package/src/actor/protocol/old.ts +416 -0
  238. package/src/actor/protocol/serde.ts +222 -0
  239. package/src/actor/router-endpoints.ts +400 -0
  240. package/src/actor/router-websocket-endpoints.test.ts +54 -0
  241. package/src/actor/router-websocket-endpoints.ts +405 -0
  242. package/src/actor/router.ts +380 -0
  243. package/src/actor/schedule.ts +17 -0
  244. package/src/actor/schema.ts +291 -0
  245. package/src/actor/utils.test.ts +48 -0
  246. package/src/actor/utils.ts +158 -0
  247. package/src/client/actor-common.ts +32 -0
  248. package/src/client/actor-conn.ts +1262 -0
  249. package/src/client/actor-handle.ts +344 -0
  250. package/src/client/actor-query.ts +112 -0
  251. package/src/client/client.ts +558 -0
  252. package/src/client/config.ts +151 -0
  253. package/src/client/errors.ts +76 -0
  254. package/src/client/log.ts +5 -0
  255. package/src/client/mod.browser.ts +2 -0
  256. package/src/client/mod.ts +70 -0
  257. package/src/client/queue.ts +146 -0
  258. package/src/client/raw-utils.ts +149 -0
  259. package/src/client/test.ts +44 -0
  260. package/src/client/utils.ts +252 -0
  261. package/src/common/actor-router-consts.ts +59 -0
  262. package/src/common/cors.ts +57 -0
  263. package/src/common/eventsource-interface.ts +47 -0
  264. package/src/common/eventsource.ts +44 -0
  265. package/src/common/inline-websocket-adapter.ts +154 -0
  266. package/src/common/log-levels.ts +27 -0
  267. package/src/common/log.ts +229 -0
  268. package/src/common/logfmt.ts +221 -0
  269. package/src/common/network.ts +2 -0
  270. package/src/common/router.ts +174 -0
  271. package/src/common/utils.ts +339 -0
  272. package/src/common/websocket-interface.ts +7 -0
  273. package/src/common/websocket.ts +43 -0
  274. package/src/db/config.ts +100 -0
  275. package/src/db/drizzle/mod.ts +226 -0
  276. package/src/db/drizzle/sqlite-core.ts +22 -0
  277. package/src/db/mod.ts +125 -0
  278. package/src/db/shared.ts +92 -0
  279. package/src/db/sqlite-vfs.ts +12 -0
  280. package/src/devtools-loader/index.ts +33 -0
  281. package/src/devtools-loader/log.ts +5 -0
  282. package/src/driver-helpers/mod.ts +33 -0
  283. package/src/driver-helpers/utils.ts +54 -0
  284. package/src/driver-test-suite/log.ts +5 -0
  285. package/src/driver-test-suite/mod.ts +293 -0
  286. package/src/driver-test-suite/test-inline-client-driver.ts +307 -0
  287. package/src/driver-test-suite/tests/access-control.ts +218 -0
  288. package/src/driver-test-suite/tests/action-features.ts +203 -0
  289. package/src/driver-test-suite/tests/actor-conn-hibernation.ts +152 -0
  290. package/src/driver-test-suite/tests/actor-conn-state.ts +300 -0
  291. package/src/driver-test-suite/tests/actor-conn.ts +596 -0
  292. package/src/driver-test-suite/tests/actor-db-raw.ts +73 -0
  293. package/src/driver-test-suite/tests/actor-db.ts +477 -0
  294. package/src/driver-test-suite/tests/actor-destroy.ts +294 -0
  295. package/src/driver-test-suite/tests/actor-driver.ts +18 -0
  296. package/src/driver-test-suite/tests/actor-error-handling.ts +150 -0
  297. package/src/driver-test-suite/tests/actor-handle.ts +312 -0
  298. package/src/driver-test-suite/tests/actor-inline-client.ts +163 -0
  299. package/src/driver-test-suite/tests/actor-inspector.ts +264 -0
  300. package/src/driver-test-suite/tests/actor-kv.ts +65 -0
  301. package/src/driver-test-suite/tests/actor-metadata.ts +116 -0
  302. package/src/driver-test-suite/tests/actor-onstatechange.ts +95 -0
  303. package/src/driver-test-suite/tests/actor-queue.ts +325 -0
  304. package/src/driver-test-suite/tests/actor-run.ts +181 -0
  305. package/src/driver-test-suite/tests/actor-schedule.ts +97 -0
  306. package/src/driver-test-suite/tests/actor-sleep.ts +415 -0
  307. package/src/driver-test-suite/tests/actor-state.ts +54 -0
  308. package/src/driver-test-suite/tests/actor-stateless.ts +70 -0
  309. package/src/driver-test-suite/tests/actor-vars.ts +97 -0
  310. package/src/driver-test-suite/tests/actor-workflow.ts +118 -0
  311. package/src/driver-test-suite/tests/manager-driver.ts +388 -0
  312. package/src/driver-test-suite/tests/raw-http-direct-registry.ts +227 -0
  313. package/src/driver-test-suite/tests/raw-http-request-properties.ts +454 -0
  314. package/src/driver-test-suite/tests/raw-http.ts +359 -0
  315. package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +393 -0
  316. package/src/driver-test-suite/tests/raw-websocket.ts +513 -0
  317. package/src/driver-test-suite/tests/request-access.ts +240 -0
  318. package/src/driver-test-suite/utils.ts +80 -0
  319. package/src/drivers/default.ts +38 -0
  320. package/src/drivers/engine/actor-driver.ts +1027 -0
  321. package/src/drivers/engine/config.ts +43 -0
  322. package/src/drivers/engine/log.ts +5 -0
  323. package/src/drivers/engine/mod.ts +36 -0
  324. package/src/drivers/file-system/actor.ts +102 -0
  325. package/src/drivers/file-system/global-state.ts +1445 -0
  326. package/src/drivers/file-system/kv-limits.ts +70 -0
  327. package/src/drivers/file-system/log.ts +5 -0
  328. package/src/drivers/file-system/manager.ts +300 -0
  329. package/src/drivers/file-system/mod.ts +78 -0
  330. package/src/drivers/file-system/sqlite-runtime.ts +210 -0
  331. package/src/drivers/file-system/utils.ts +125 -0
  332. package/src/engine-process/constants.ts +2 -0
  333. package/src/engine-process/log.ts +5 -0
  334. package/src/engine-process/mod.ts +464 -0
  335. package/src/globals.d.ts +35 -0
  336. package/src/inspector/actor-inspector.ts +352 -0
  337. package/src/inspector/config.ts +49 -0
  338. package/src/inspector/handler.ts +273 -0
  339. package/src/inspector/log.ts +5 -0
  340. package/src/inspector/mod.browser.ts +8 -0
  341. package/src/inspector/mod.ts +4 -0
  342. package/src/inspector/serve-ui.ts +40 -0
  343. package/src/inspector/transport.ts +18 -0
  344. package/src/inspector/utils.ts +32 -0
  345. package/src/manager/driver.ts +106 -0
  346. package/src/manager/gateway.ts +668 -0
  347. package/src/manager/log.ts +5 -0
  348. package/src/manager/mod.ts +2 -0
  349. package/src/manager/protocol/mod.ts +22 -0
  350. package/src/manager/protocol/query.ts +85 -0
  351. package/src/manager/router-schema.ts +22 -0
  352. package/src/manager/router.ts +660 -0
  353. package/src/manager-api/actors.ts +83 -0
  354. package/src/manager-api/common.ts +4 -0
  355. package/src/mod.ts +24 -0
  356. package/src/registry/config/driver.ts +21 -0
  357. package/src/registry/config/index.ts +510 -0
  358. package/src/registry/config/legacy-runner.ts +157 -0
  359. package/src/registry/config/runner.ts +21 -0
  360. package/src/registry/config/serverless.ts +94 -0
  361. package/src/registry/index.ts +194 -0
  362. package/src/registry/log.ts +5 -0
  363. package/src/remote-manager-driver/actor-http-client.ts +84 -0
  364. package/src/remote-manager-driver/actor-websocket-client.ts +81 -0
  365. package/src/remote-manager-driver/api-endpoints.ts +159 -0
  366. package/src/remote-manager-driver/api-utils.ts +69 -0
  367. package/src/remote-manager-driver/log.ts +5 -0
  368. package/src/remote-manager-driver/metadata.ts +64 -0
  369. package/src/remote-manager-driver/mod.ts +414 -0
  370. package/src/remote-manager-driver/ws-proxy.ts +189 -0
  371. package/src/schemas/actor-inspector/mod.ts +1 -0
  372. package/src/schemas/actor-inspector/versioned.ts +233 -0
  373. package/src/schemas/actor-persist/mod.ts +1 -0
  374. package/src/schemas/actor-persist/versioned.ts +217 -0
  375. package/src/schemas/client-protocol/mod.ts +1 -0
  376. package/src/schemas/client-protocol/versioned.ts +330 -0
  377. package/src/schemas/client-protocol-zod/mod.ts +118 -0
  378. package/src/schemas/file-system-driver/mod.ts +1 -0
  379. package/src/schemas/file-system-driver/versioned.ts +135 -0
  380. package/src/schemas/persist/mod.ts +1 -0
  381. package/src/schemas/transport/mod.ts +1 -0
  382. package/src/serde.ts +138 -0
  383. package/src/serve-test-suite/mod.ts +148 -0
  384. package/src/serverless/configure.ts +82 -0
  385. package/src/serverless/log.ts +5 -0
  386. package/src/serverless/router.test.ts +299 -0
  387. package/src/serverless/router.ts +215 -0
  388. package/src/test/log.ts +5 -0
  389. package/src/test/mod.ts +99 -0
  390. package/src/utils/crypto.ts +24 -0
  391. package/src/utils/endpoint-parser.test.ts +202 -0
  392. package/src/utils/endpoint-parser.ts +124 -0
  393. package/src/utils/env-vars.ts +78 -0
  394. package/src/utils/node.ts +178 -0
  395. package/src/utils/router.ts +83 -0
  396. package/src/utils/serve.ts +212 -0
  397. package/src/utils.test.ts +34 -0
  398. package/src/utils.ts +437 -0
  399. package/src/workflow/constants.ts +2 -0
  400. package/src/workflow/context.ts +597 -0
  401. package/src/workflow/driver.ts +194 -0
  402. package/src/workflow/inspector.ts +268 -0
  403. package/src/workflow/mod.ts +128 -0
@@ -0,0 +1,215 @@
1
+ import invariant from "invariant";
2
+ import {
3
+ EndpointMismatch,
4
+ InvalidRequest,
5
+ NamespaceMismatch,
6
+ } from "@/actor/errors";
7
+ import { convertRegistryConfigToClientConfig } from "@/client/config";
8
+ import { handleHealthRequest, handleMetadataRequest } from "@/common/router";
9
+ import { ServerlessStartHeadersSchema } from "@/manager/router-schema";
10
+ import { createClientWithDriver } from "@/mod";
11
+ import type { DriverConfig, RegistryConfig } from "@/registry/config";
12
+ import { RemoteManagerDriver } from "@/remote-manager-driver/mod";
13
+ import { createRouter } from "@/utils/router";
14
+ import { logger } from "./log";
15
+
16
+ export function buildServerlessRouter(
17
+ driverConfig: DriverConfig,
18
+ config: RegistryConfig,
19
+ ) {
20
+ return createRouter(config.serverless.basePath, (router) => {
21
+ // GET /
22
+ router.get("/", (c) => {
23
+ return c.text(
24
+ "This is a RivetKit server.\n\nLearn more at https://rivetkit.org",
25
+ );
26
+ });
27
+
28
+ // Serverless start endpoint
29
+ router.get("/start", async (c) => {
30
+ // Parse headers
31
+ const parseResult = ServerlessStartHeadersSchema.safeParse({
32
+ endpoint: c.req.header("x-rivet-endpoint"),
33
+ token: c.req.header("x-rivet-token") ?? undefined,
34
+ totalSlots: c.req.header("x-rivet-total-slots"),
35
+ runnerName: c.req.header("x-rivet-runner-name"),
36
+ namespace: c.req.header("x-rivet-namespace-name"),
37
+ });
38
+ if (!parseResult.success) {
39
+ throw new InvalidRequest(
40
+ parseResult.error.issues[0]?.message ??
41
+ "invalid serverless start headers",
42
+ );
43
+ }
44
+ const { endpoint, token, totalSlots, runnerName, namespace } =
45
+ parseResult.data;
46
+
47
+ logger().debug({
48
+ msg: "received serverless runner start request",
49
+ endpoint,
50
+ totalSlots,
51
+ runnerName,
52
+ namespace,
53
+ });
54
+
55
+ // Validate endpoint and namespace match config to catch
56
+ // misconfiguration or malicious requests.
57
+ //
58
+ // Only verify if namespace matches if endpoint configured since
59
+ // configuring an endpoint indicates you want to assert the
60
+ // incoming serverless requests.
61
+ if (config.endpoint) {
62
+ if (!endpointsMatch(endpoint, config.endpoint)) {
63
+ throw new EndpointMismatch(config.endpoint, endpoint);
64
+ }
65
+
66
+ if (namespace !== config.namespace) {
67
+ throw new NamespaceMismatch(config.namespace, namespace);
68
+ }
69
+ }
70
+
71
+ // Convert config to runner config
72
+ const newConfig: RegistryConfig = {
73
+ ...config,
74
+ endpoint: endpoint,
75
+ namespace: namespace,
76
+ token: token,
77
+ runner: {
78
+ ...config.runner,
79
+ totalSlots: totalSlots,
80
+ runnerName: runnerName,
81
+ // Not supported on serverless
82
+ runnerKey: undefined,
83
+ },
84
+ };
85
+
86
+ // Create manager driver on demand based on the properties provided
87
+ // by headers
88
+ //
89
+ // NOTE: This relies on the `newConfig.runner.runnerName` to
90
+ // configure which runner to create actors on.
91
+ const managerDriver = new RemoteManagerDriver(
92
+ convertRegistryConfigToClientConfig(newConfig),
93
+ );
94
+ const client = createClientWithDriver(managerDriver);
95
+
96
+ // Create new actor driver with updated config
97
+ const actorDriver = driverConfig.actor(
98
+ newConfig,
99
+ managerDriver,
100
+ client,
101
+ );
102
+ invariant(
103
+ actorDriver.serverlessHandleStart,
104
+ "missing serverlessHandleStart on ActorDriver",
105
+ );
106
+
107
+ return await actorDriver.serverlessHandleStart(c);
108
+ });
109
+
110
+ router.get("/health", (c) => handleHealthRequest(c));
111
+
112
+ router.get("/metadata", (c) =>
113
+ handleMetadataRequest(
114
+ c,
115
+ config,
116
+ { serverless: {} },
117
+ config.publicEndpoint,
118
+ config.publicNamespace,
119
+ config.publicToken,
120
+ ),
121
+ );
122
+ });
123
+ }
124
+
125
+ /**
126
+ * Normalizes a URL for comparison by extracting protocol, host, port, and pathname.
127
+ * Normalizes loopback addresses (127.0.0.1, 0.0.0.0, ::1) to localhost for consistent comparison.
128
+ * Normalizes regional endpoints (api-*.domain) to base endpoints (api.domain).
129
+ * Returns null if the URL is invalid.
130
+ */
131
+ export function normalizeEndpointUrl(url: string): string | null {
132
+ try {
133
+ const parsed = new URL(url);
134
+ // Normalize pathname by removing trailing slash (except for root)
135
+ const pathname =
136
+ parsed.pathname === "/" ? "/" : parsed.pathname.replace(/\/+$/, "");
137
+
138
+ // Normalize loopback addresses to localhost
139
+ let hostname = isLoopbackAddress(parsed.hostname)
140
+ ? "localhost"
141
+ : parsed.hostname;
142
+
143
+ // Normalize regional endpoints (api-region.domain) to base endpoints (api.domain)
144
+ // HACK: This is specific to Rivet Cloud and will not work for self-hosted
145
+ // engines with different regional endpoint naming conventions.
146
+ hostname = normalizeRegionalHostname(hostname);
147
+
148
+ // Reconstruct host with normalized hostname and port
149
+ const host = parsed.port ? `${hostname}:${parsed.port}` : hostname;
150
+
151
+ // Reconstruct normalized URL with protocol, host, and pathname
152
+ return `${parsed.protocol}//${host}${pathname}`;
153
+ } catch {
154
+ return null;
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Normalizes regional hostnames (api-region.domain) to base hostnames (api.domain).
160
+ * Only applies to rivet.dev domains.
161
+ *
162
+ * Examples:
163
+ * - api-us-west-1.rivet.dev -> api.rivet.dev
164
+ * - api-lax.staging.rivet.dev -> api.staging.rivet.dev
165
+ * - api.rivet.dev -> api.rivet.dev (unchanged)
166
+ * - api-us-west-1.example.com -> api-us-west-1.example.com (unchanged, not rivet.dev)
167
+ * - foo-bar.rivet.dev -> foo-bar.rivet.dev (unchanged, not api- prefix)
168
+ */
169
+ function normalizeRegionalHostname(hostname: string): string {
170
+ // Only apply to rivet.dev domains
171
+ if (!hostname.endsWith(".rivet.dev")) {
172
+ return hostname;
173
+ }
174
+
175
+ if (!hostname.startsWith("api-")) {
176
+ return hostname;
177
+ }
178
+
179
+ // Find the first dot after "api-"
180
+ const withoutPrefix = hostname.slice(4); // Remove "api-"
181
+ const firstDotIndex = withoutPrefix.indexOf(".");
182
+ if (firstDotIndex === -1) {
183
+ return hostname;
184
+ }
185
+
186
+ // Extract the domain part and prepend "api."
187
+ const domain = withoutPrefix.slice(firstDotIndex + 1);
188
+ return `api.${domain}`;
189
+ }
190
+
191
+ /**
192
+ * Compares two endpoint URLs after normalization.
193
+ * Returns true if they match (same protocol, host, port, and path).
194
+ */
195
+ export function endpointsMatch(a: string, b: string): boolean {
196
+ const normalizedA = normalizeEndpointUrl(a);
197
+ const normalizedB = normalizeEndpointUrl(b);
198
+ if (normalizedA === null || normalizedB === null) {
199
+ // If either URL is invalid, fall back to string comparison
200
+ return a === b;
201
+ }
202
+ return normalizedA === normalizedB;
203
+ }
204
+
205
+ /**
206
+ * Checks if a hostname is a loopback address that should be normalized to localhost.
207
+ */
208
+ function isLoopbackAddress(hostname: string): boolean {
209
+ return (
210
+ hostname === "127.0.0.1" ||
211
+ hostname === "0.0.0.0" ||
212
+ hostname === "::1" ||
213
+ hostname === "[::1]"
214
+ );
215
+ }
@@ -0,0 +1,5 @@
1
+ import { getLogger } from "@/common/log";
2
+
3
+ export function logger() {
4
+ return getLogger("test");
5
+ }
@@ -0,0 +1,99 @@
1
+ import { serve as honoServe } from "@hono/node-server";
2
+ import { createNodeWebSocket } from "@hono/node-ws";
3
+ import invariant from "invariant";
4
+ import { type TestContext, vi } from "vitest";
5
+ import { ClientConfigSchema } from "@/client/config";
6
+ import { type Client, createClient } from "@/client/mod";
7
+ import { createFileSystemOrMemoryDriver } from "@/drivers/file-system/mod";
8
+ import { createClientWithDriver, type Registry } from "@/mod";
9
+ import { RegistryConfig, RegistryConfigSchema } from "@/registry/config";
10
+ import { buildManagerRouter } from "@/manager/router";
11
+ import { logger } from "./log";
12
+
13
+ export interface SetupTestResult<A extends Registry<any>> {
14
+ client: Client<A>;
15
+ }
16
+
17
+ // Must use `TestContext` since global hooks do not work when running concurrently
18
+ export async function setupTest<A extends Registry<any>>(
19
+ c: TestContext,
20
+ registry: A,
21
+ ): Promise<SetupTestResult<A>> {
22
+ // Force enable test mode
23
+ registry.config.test = { ...registry.config.test, enabled: true };
24
+
25
+ // Create driver
26
+ const driver = createFileSystemOrMemoryDriver(
27
+ true,
28
+ { path: `/tmp/rivetkit-test-${crypto.randomUUID()}` },
29
+ );
30
+
31
+ // Build driver config
32
+ // biome-ignore lint/style/useConst: Assigned later
33
+ let upgradeWebSocket: any;
34
+ registry.config.driver = driver;
35
+ registry.config.inspector = {
36
+ enabled: true,
37
+ token: () => "token",
38
+ };
39
+
40
+ // Create router
41
+ const parsedConfig = registry.parseConfig();
42
+ const managerDriver = driver.manager?.(parsedConfig);
43
+ invariant(managerDriver, "missing manager driver");
44
+ const getUpgradeWebSocket = () => upgradeWebSocket;
45
+ managerDriver.setGetUpgradeWebSocket(getUpgradeWebSocket);
46
+ // const internalClient = createClientWithDriver(
47
+ // managerDriver,
48
+ // ClientConfigSchema.parse({}),
49
+ // );
50
+ const { router } = buildManagerRouter(
51
+ parsedConfig,
52
+ managerDriver,
53
+ getUpgradeWebSocket,
54
+ );
55
+
56
+ // Inject WebSocket
57
+ const nodeWebSocket = createNodeWebSocket({ app: router });
58
+ upgradeWebSocket = nodeWebSocket.upgradeWebSocket;
59
+
60
+ // TODO: I think this whole function is fucked, we should probably switch to calling registry.serve() directly
61
+ // Start server
62
+ const server = honoServe({
63
+ fetch: router.fetch,
64
+ hostname: "127.0.0.1",
65
+ port: 0,
66
+ });
67
+ if (!server.listening) {
68
+ await new Promise<void>((resolve) => {
69
+ server.once("listening", () => resolve());
70
+ });
71
+ }
72
+ invariant(
73
+ nodeWebSocket.injectWebSocket !== undefined,
74
+ "should have injectWebSocket",
75
+ );
76
+ nodeWebSocket.injectWebSocket(server);
77
+ const address = server.address();
78
+ invariant(address && typeof address !== "string", "missing server address");
79
+ const port = address.port;
80
+ const endpoint = `http://127.0.0.1:${port}`;
81
+
82
+ logger().info({ msg: "test server listening", port });
83
+
84
+ // Cleanup on test finish
85
+ c.onTestFinished(async () => {
86
+ await new Promise((resolve) => server.close(() => resolve(undefined)));
87
+ });
88
+
89
+ // Create client
90
+ const client = createClient<A>({
91
+ endpoint,
92
+ namespace: "default",
93
+ runnerName: "default",
94
+ disableMetadataLookup: true,
95
+ });
96
+ c.onTestFinished(async () => await client.dispose());
97
+
98
+ return { client };
99
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Timing-safe comparison of two Uint8Arrays or strings.
3
+ * This prevents timing attacks by always comparing all bytes.
4
+ */
5
+ export function timingSafeEqual(
6
+ a: Uint8Array | string,
7
+ b: Uint8Array | string,
8
+ ): boolean {
9
+ const encoder = new TextEncoder();
10
+ const bufferA = typeof a === "string" ? encoder.encode(a) : a;
11
+ const bufferB = typeof b === "string" ? encoder.encode(b) : b;
12
+
13
+ // Pad to max length to avoid leaking length information
14
+ const maxLength = Math.max(bufferA.byteLength, bufferB.byteLength);
15
+ let result = bufferA.byteLength ^ bufferB.byteLength;
16
+
17
+ for (let i = 0; i < maxLength; i++) {
18
+ const byteA = i < bufferA.byteLength ? bufferA[i] : 0;
19
+ const byteB = i < bufferB.byteLength ? bufferB[i] : 0;
20
+ result |= byteA ^ byteB;
21
+ }
22
+
23
+ return result === 0;
24
+ }
@@ -0,0 +1,202 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import type { z } from "zod/v4";
3
+ import { tryParseEndpoint } from "./endpoint-parser";
4
+
5
+ // Helper to create a mock Zod refinement context for testing
6
+ function createMockCtx(): { ctx: z.RefinementCtx; issues: z.ZodIssue[] } {
7
+ const issues: z.ZodIssue[] = [];
8
+ const ctx = {
9
+ addIssue: (issue: z.IssueData) => {
10
+ issues.push(issue as z.ZodIssue);
11
+ },
12
+ path: [],
13
+ value: undefined,
14
+ issues: [],
15
+ } as unknown as z.RefinementCtx;
16
+ return { ctx, issues };
17
+ }
18
+
19
+ describe("tryParseEndpoint", () => {
20
+ describe("basic parsing", () => {
21
+ test("parses endpoint with full auth", () => {
22
+ const { ctx, issues } = createMockCtx();
23
+ const result = tryParseEndpoint(ctx, {
24
+ endpoint: "https://foo:bar@api.rivet.dev",
25
+ });
26
+ expect(issues).toHaveLength(0);
27
+ expect(result).toEqual({
28
+ endpoint: "https://api.rivet.dev/",
29
+ namespace: "foo",
30
+ token: "bar",
31
+ });
32
+ });
33
+
34
+ test("parses endpoint with namespace only", () => {
35
+ const { ctx, issues } = createMockCtx();
36
+ const result = tryParseEndpoint(ctx, {
37
+ endpoint: "https://foo@api.rivet.dev",
38
+ });
39
+ expect(issues).toHaveLength(0);
40
+ expect(result).toEqual({
41
+ endpoint: "https://api.rivet.dev/",
42
+ namespace: "foo",
43
+ token: undefined,
44
+ });
45
+ });
46
+
47
+ test("parses endpoint without auth", () => {
48
+ const { ctx, issues } = createMockCtx();
49
+ const result = tryParseEndpoint(ctx, {
50
+ endpoint: "https://api.rivet.dev",
51
+ });
52
+ expect(issues).toHaveLength(0);
53
+ expect(result).toEqual({
54
+ endpoint: "https://api.rivet.dev/",
55
+ namespace: undefined,
56
+ token: undefined,
57
+ });
58
+ });
59
+
60
+ test("preserves path", () => {
61
+ const { ctx, issues } = createMockCtx();
62
+ const result = tryParseEndpoint(ctx, {
63
+ endpoint: "https://foo:bar@api.rivet.dev/v1/actors",
64
+ });
65
+ expect(issues).toHaveLength(0);
66
+ expect(result).toEqual({
67
+ endpoint: "https://api.rivet.dev/v1/actors",
68
+ namespace: "foo",
69
+ token: "bar",
70
+ });
71
+ });
72
+ });
73
+
74
+ describe("validation errors", () => {
75
+ test("adds issue for invalid URL", () => {
76
+ const { ctx, issues } = createMockCtx();
77
+ const result = tryParseEndpoint(ctx, { endpoint: "not-a-url" });
78
+ expect(result).toBeUndefined();
79
+ expect(issues).toHaveLength(1);
80
+ expect(issues[0]?.message).toContain("invalid URL");
81
+ });
82
+
83
+ test("adds issue for query string", () => {
84
+ const { ctx, issues } = createMockCtx();
85
+ const result = tryParseEndpoint(ctx, {
86
+ endpoint: "https://foo:bar@api.rivet.dev?region=us",
87
+ });
88
+ expect(result).toBeUndefined();
89
+ expect(issues).toHaveLength(1);
90
+ expect(issues[0]?.message).toBe("endpoint cannot contain a query string");
91
+ });
92
+
93
+ test("adds issue for fragment", () => {
94
+ const { ctx, issues } = createMockCtx();
95
+ const result = tryParseEndpoint(ctx, {
96
+ endpoint: "https://foo:bar@api.rivet.dev#section",
97
+ });
98
+ expect(result).toBeUndefined();
99
+ expect(issues).toHaveLength(1);
100
+ expect(issues[0]?.message).toBe("endpoint cannot contain a fragment");
101
+ });
102
+
103
+ test("adds issue for token without namespace", () => {
104
+ const { ctx, issues } = createMockCtx();
105
+ const result = tryParseEndpoint(ctx, {
106
+ endpoint: "https://:token@api.rivet.dev",
107
+ });
108
+ expect(result).toBeUndefined();
109
+ expect(issues).toHaveLength(1);
110
+ expect(issues[0]?.message).toBe(
111
+ "endpoint cannot have a token without a namespace",
112
+ );
113
+ });
114
+ });
115
+
116
+ describe("duplicate credential checking", () => {
117
+ test("adds issue when namespace in URL and config", () => {
118
+ const { ctx, issues } = createMockCtx();
119
+ const result = tryParseEndpoint(ctx, {
120
+ endpoint: "https://url-ns@api.rivet.dev",
121
+ path: ["endpoint"],
122
+ namespace: "config-ns",
123
+ });
124
+ // Still returns result, but adds issue
125
+ expect(result).toEqual({
126
+ endpoint: "https://api.rivet.dev/",
127
+ namespace: "url-ns",
128
+ token: undefined,
129
+ });
130
+ expect(issues).toHaveLength(1);
131
+ expect(issues[0]?.message).toContain(
132
+ "cannot specify namespace both in endpoint URL and as a separate config option",
133
+ );
134
+ expect(issues[0]?.path).toEqual(["namespace"]);
135
+ });
136
+
137
+ test("adds issue when token in URL and config", () => {
138
+ const { ctx, issues } = createMockCtx();
139
+ const result = tryParseEndpoint(ctx, {
140
+ endpoint: "https://ns:url-token@api.rivet.dev",
141
+ path: ["endpoint"],
142
+ token: "config-token",
143
+ });
144
+ // Still returns result, but adds issue
145
+ expect(result).toEqual({
146
+ endpoint: "https://api.rivet.dev/",
147
+ namespace: "ns",
148
+ token: "url-token",
149
+ });
150
+ expect(issues).toHaveLength(1);
151
+ expect(issues[0]?.message).toContain(
152
+ "cannot specify token both in endpoint URL and as a separate config option",
153
+ );
154
+ expect(issues[0]?.path).toEqual(["token"]);
155
+ });
156
+
157
+ test("adds issues for both namespace and token duplicates", () => {
158
+ const { ctx, issues } = createMockCtx();
159
+ const result = tryParseEndpoint(ctx, {
160
+ endpoint: "https://url-ns:url-token@api.rivet.dev",
161
+ path: ["endpoint"],
162
+ namespace: "config-ns",
163
+ token: "config-token",
164
+ });
165
+ expect(result).toBeDefined();
166
+ expect(issues).toHaveLength(2);
167
+ });
168
+
169
+ test("no issue when namespace only in URL", () => {
170
+ const { ctx, issues } = createMockCtx();
171
+ const result = tryParseEndpoint(ctx, {
172
+ endpoint: "https://url-ns@api.rivet.dev",
173
+ path: ["endpoint"],
174
+ token: "config-token",
175
+ });
176
+ expect(result).toBeDefined();
177
+ expect(issues).toHaveLength(0);
178
+ });
179
+
180
+ test("no issue when namespace only in config", () => {
181
+ const { ctx, issues } = createMockCtx();
182
+ const result = tryParseEndpoint(ctx, {
183
+ endpoint: "https://api.rivet.dev",
184
+ path: ["endpoint"],
185
+ namespace: "config-ns",
186
+ });
187
+ expect(result).toBeDefined();
188
+ expect(issues).toHaveLength(0);
189
+ });
190
+ });
191
+
192
+ describe("custom path", () => {
193
+ test("uses custom path in error issues", () => {
194
+ const { ctx, issues } = createMockCtx();
195
+ tryParseEndpoint(ctx, {
196
+ endpoint: "not-a-url",
197
+ path: ["serverless", "publicEndpoint"],
198
+ });
199
+ expect(issues[0]?.path).toEqual(["serverless", "publicEndpoint"]);
200
+ });
201
+ });
202
+ });
@@ -0,0 +1,124 @@
1
+ import { z } from "zod/v4";
2
+
3
+ export interface ParsedEndpoint {
4
+ endpoint: string;
5
+ namespace: string | undefined;
6
+ token: string | undefined;
7
+ }
8
+
9
+ export interface TryParseEndpointOptions {
10
+ /** The endpoint URL string to parse */
11
+ endpoint: string;
12
+ /** Path prefix for error messages (default: ["endpoint"]) */
13
+ path?: (string | number)[];
14
+ /** Namespace from config, to check for duplicate specification */
15
+ namespace?: string;
16
+ /** Token from config, to check for duplicate specification */
17
+ token?: string;
18
+ }
19
+
20
+ /**
21
+ * Parses an endpoint URL that may contain auth syntax for namespace and token.
22
+ *
23
+ * Uses ctx.addIssue for clean error reporting in Zod transforms.
24
+ *
25
+ * Supports formats like:
26
+ * - `https://namespace:token@api.rivet.dev`
27
+ * - `https://namespace@api.rivet.dev` (namespace only, no token)
28
+ * - `https://api.rivet.dev` (no auth)
29
+ * - `https://namespace:token@api.rivet.dev/path` (with path)
30
+ *
31
+ * Query strings and fragments are not allowed as they may conflict with
32
+ * runtime parameters.
33
+ *
34
+ * @param ctx - Zod refinement context for error reporting
35
+ * @param options - Parsing options including endpoint, path, and config values
36
+ * @returns ParsedEndpoint on success, undefined on error (after adding issues to ctx)
37
+ */
38
+ export function tryParseEndpoint(
39
+ ctx: z.RefinementCtx,
40
+ options: TryParseEndpointOptions,
41
+ ): ParsedEndpoint | undefined {
42
+ const { endpoint, path = ["endpoint"], namespace: configNamespace, token: configToken } = options;
43
+ // Parse the URL
44
+ let url: URL;
45
+ try {
46
+ url = new URL(endpoint);
47
+ } catch {
48
+ ctx.addIssue({
49
+ code: "custom",
50
+ message: `invalid URL: ${endpoint}`,
51
+ path,
52
+ });
53
+ return undefined;
54
+ }
55
+
56
+ // Reject query strings
57
+ if (url.search) {
58
+ ctx.addIssue({
59
+ code: "custom",
60
+ message: "endpoint cannot contain a query string",
61
+ path,
62
+ });
63
+ return undefined;
64
+ }
65
+
66
+ // Reject fragments
67
+ if (url.hash) {
68
+ ctx.addIssue({
69
+ code: "custom",
70
+ message: "endpoint cannot contain a fragment",
71
+ path,
72
+ });
73
+ return undefined;
74
+ }
75
+
76
+ // Extract namespace and token from username and password
77
+ // URL stores these as percent-encoded, so we need to decode them
78
+ const namespace = url.username
79
+ ? decodeURIComponent(url.username)
80
+ : undefined;
81
+ const token = url.password ? decodeURIComponent(url.password) : undefined;
82
+
83
+ // Reject token without namespace (e.g., https://:token@api.rivet.dev)
84
+ if (token && !namespace) {
85
+ ctx.addIssue({
86
+ code: "custom",
87
+ message: "endpoint cannot have a token without a namespace",
88
+ path,
89
+ });
90
+ return undefined;
91
+ }
92
+
93
+ // Check for duplicate credentials (specified both in URL and config)
94
+ if (namespace && configNamespace) {
95
+ ctx.addIssue({
96
+ code: "custom",
97
+ message:
98
+ "cannot specify namespace both in endpoint URL and as a separate config option",
99
+ path: ["namespace"],
100
+ });
101
+ }
102
+ if (token && configToken) {
103
+ ctx.addIssue({
104
+ code: "custom",
105
+ message:
106
+ "cannot specify token both in endpoint URL and as a separate config option",
107
+ path: ["token"],
108
+ });
109
+ }
110
+
111
+ // Strip auth from the URL by clearing username and password
112
+ url.username = "";
113
+ url.password = "";
114
+
115
+ // Get the cleaned endpoint without auth
116
+ const cleanedEndpoint = url.toString();
117
+
118
+ return {
119
+ endpoint: cleanedEndpoint,
120
+ namespace,
121
+ token,
122
+ };
123
+ }
124
+