@alchemy.run/modal 0.0.0 → 2.0.0-beta.86

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 (499) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +96 -4
  3. package/lib/App.d.ts +143 -0
  4. package/lib/App.d.ts.map +1 -0
  5. package/lib/App.js +198 -0
  6. package/lib/App.js.map +1 -0
  7. package/lib/AuthProvider.d.ts +53 -0
  8. package/lib/AuthProvider.d.ts.map +1 -0
  9. package/lib/AuthProvider.js +209 -0
  10. package/lib/AuthProvider.js.map +1 -0
  11. package/lib/BindingHttp.d.ts +56 -0
  12. package/lib/BindingHttp.d.ts.map +1 -0
  13. package/lib/BindingHttp.js +50 -0
  14. package/lib/BindingHttp.js.map +1 -0
  15. package/lib/Blob.d.ts +34 -0
  16. package/lib/Blob.d.ts.map +1 -0
  17. package/lib/Blob.js +59 -0
  18. package/lib/Blob.js.map +1 -0
  19. package/lib/Bootstrap.d.ts +8 -0
  20. package/lib/Bootstrap.d.ts.map +1 -0
  21. package/lib/Bootstrap.js +26 -0
  22. package/lib/Bootstrap.js.map +1 -0
  23. package/lib/Cbor.d.ts +10 -0
  24. package/lib/Cbor.d.ts.map +1 -0
  25. package/lib/Cbor.js +177 -0
  26. package/lib/Cbor.js.map +1 -0
  27. package/lib/ConnectSandbox.d.ts +64 -0
  28. package/lib/ConnectSandbox.d.ts.map +1 -0
  29. package/lib/ConnectSandbox.js +33 -0
  30. package/lib/ConnectSandbox.js.map +1 -0
  31. package/lib/Container.d.ts +124 -0
  32. package/lib/Container.d.ts.map +1 -0
  33. package/lib/Container.js +1 -0
  34. package/lib/Container.js.map +1 -0
  35. package/lib/Contributions.d.ts +7 -0
  36. package/lib/Contributions.d.ts.map +1 -0
  37. package/lib/Contributions.js +6 -0
  38. package/lib/Contributions.js.map +1 -0
  39. package/lib/CreateDict.d.ts +83 -0
  40. package/lib/CreateDict.d.ts.map +1 -0
  41. package/lib/CreateDict.js +3 -0
  42. package/lib/CreateDict.js.map +1 -0
  43. package/lib/CreateDictHttp.d.ts +33 -0
  44. package/lib/CreateDictHttp.d.ts.map +1 -0
  45. package/lib/CreateDictHttp.js +67 -0
  46. package/lib/CreateDictHttp.js.map +1 -0
  47. package/lib/CreateImage.d.ts +98 -0
  48. package/lib/CreateImage.d.ts.map +1 -0
  49. package/lib/CreateImage.js +3 -0
  50. package/lib/CreateImage.js.map +1 -0
  51. package/lib/CreateImageHttp.d.ts +51 -0
  52. package/lib/CreateImageHttp.d.ts.map +1 -0
  53. package/lib/CreateImageHttp.js +87 -0
  54. package/lib/CreateImageHttp.js.map +1 -0
  55. package/lib/CreateQueue.d.ts +83 -0
  56. package/lib/CreateQueue.d.ts.map +1 -0
  57. package/lib/CreateQueue.js +3 -0
  58. package/lib/CreateQueue.js.map +1 -0
  59. package/lib/CreateQueueHttp.d.ts +31 -0
  60. package/lib/CreateQueueHttp.d.ts.map +1 -0
  61. package/lib/CreateQueueHttp.js +67 -0
  62. package/lib/CreateQueueHttp.js.map +1 -0
  63. package/lib/CreateSandbox.d.ts +186 -0
  64. package/lib/CreateSandbox.d.ts.map +1 -0
  65. package/lib/CreateSandbox.js +3 -0
  66. package/lib/CreateSandbox.js.map +1 -0
  67. package/lib/CreateSandboxHttp.d.ts +17 -0
  68. package/lib/CreateSandboxHttp.d.ts.map +1 -0
  69. package/lib/CreateSandboxHttp.js +117 -0
  70. package/lib/CreateSandboxHttp.js.map +1 -0
  71. package/lib/CreateSecret.d.ts +95 -0
  72. package/lib/CreateSecret.d.ts.map +1 -0
  73. package/lib/CreateSecret.js +3 -0
  74. package/lib/CreateSecret.js.map +1 -0
  75. package/lib/CreateSecretHttp.d.ts +24 -0
  76. package/lib/CreateSecretHttp.d.ts.map +1 -0
  77. package/lib/CreateSecretHttp.js +60 -0
  78. package/lib/CreateSecretHttp.js.map +1 -0
  79. package/lib/CreateVolume.d.ts +84 -0
  80. package/lib/CreateVolume.d.ts.map +1 -0
  81. package/lib/CreateVolume.js +3 -0
  82. package/lib/CreateVolume.js.map +1 -0
  83. package/lib/CreateVolumeHttp.d.ts +32 -0
  84. package/lib/CreateVolumeHttp.d.ts.map +1 -0
  85. package/lib/CreateVolumeHttp.js +69 -0
  86. package/lib/CreateVolumeHttp.js.map +1 -0
  87. package/lib/Credentials.d.ts +32 -0
  88. package/lib/Credentials.d.ts.map +1 -0
  89. package/lib/Credentials.js +44 -0
  90. package/lib/Credentials.js.map +1 -0
  91. package/lib/Dict.d.ts +147 -0
  92. package/lib/Dict.d.ts.map +1 -0
  93. package/lib/Dict.js +175 -0
  94. package/lib/Dict.js.map +1 -0
  95. package/lib/DictClient.d.ts +55 -0
  96. package/lib/DictClient.d.ts.map +1 -0
  97. package/lib/DictClient.js +89 -0
  98. package/lib/DictClient.js.map +1 -0
  99. package/lib/Domain.d.ts +86 -0
  100. package/lib/Domain.d.ts.map +1 -0
  101. package/lib/Domain.js +113 -0
  102. package/lib/Domain.js.map +1 -0
  103. package/lib/Endpoint.d.ts +181 -0
  104. package/lib/Endpoint.d.ts.map +1 -0
  105. package/lib/Endpoint.js +283 -0
  106. package/lib/Endpoint.js.map +1 -0
  107. package/lib/Environment.d.ts +174 -0
  108. package/lib/Environment.d.ts.map +1 -0
  109. package/lib/Environment.js +244 -0
  110. package/lib/Environment.js.map +1 -0
  111. package/lib/FetchServer.d.ts +105 -0
  112. package/lib/FetchServer.d.ts.map +1 -0
  113. package/lib/FetchServer.js +3 -0
  114. package/lib/FetchServer.js.map +1 -0
  115. package/lib/FetchServerHttp.d.ts +21 -0
  116. package/lib/FetchServerHttp.d.ts.map +1 -0
  117. package/lib/FetchServerHttp.js +84 -0
  118. package/lib/FetchServerHttp.js.map +1 -0
  119. package/lib/Function.d.ts +236 -0
  120. package/lib/Function.d.ts.map +1 -0
  121. package/lib/Function.js +273 -0
  122. package/lib/Function.js.map +1 -0
  123. package/lib/FunctionAutoscaler.d.ts +99 -0
  124. package/lib/FunctionAutoscaler.d.ts.map +1 -0
  125. package/lib/FunctionAutoscaler.js +136 -0
  126. package/lib/FunctionAutoscaler.js.map +1 -0
  127. package/lib/FunctionTarget.d.ts +61 -0
  128. package/lib/FunctionTarget.d.ts.map +1 -0
  129. package/lib/FunctionTarget.js +136 -0
  130. package/lib/FunctionTarget.js.map +1 -0
  131. package/lib/Image.d.ts +159 -0
  132. package/lib/Image.d.ts.map +1 -0
  133. package/lib/Image.js +203 -0
  134. package/lib/Image.js.map +1 -0
  135. package/lib/ImageBuild.d.ts +108 -0
  136. package/lib/ImageBuild.d.ts.map +1 -0
  137. package/lib/ImageBuild.js +157 -0
  138. package/lib/ImageBuild.js.map +1 -0
  139. package/lib/ImagePlan.d.ts +31 -0
  140. package/lib/ImagePlan.d.ts.map +1 -0
  141. package/lib/ImagePlan.js +70 -0
  142. package/lib/ImagePlan.js.map +1 -0
  143. package/lib/InferEnv.d.ts +26 -0
  144. package/lib/InferEnv.d.ts.map +1 -0
  145. package/lib/InferEnv.js +1 -0
  146. package/lib/InferEnv.js.map +1 -0
  147. package/lib/InvokeFunction.d.ts +186 -0
  148. package/lib/InvokeFunction.d.ts.map +1 -0
  149. package/lib/InvokeFunction.js +10 -0
  150. package/lib/InvokeFunction.js.map +1 -0
  151. package/lib/InvokeFunctionHttp.d.ts +39 -0
  152. package/lib/InvokeFunctionHttp.d.ts.map +1 -0
  153. package/lib/InvokeFunctionHttp.js +210 -0
  154. package/lib/InvokeFunctionHttp.js.map +1 -0
  155. package/lib/ModalBindings.d.ts +138 -0
  156. package/lib/ModalBindings.d.ts.map +1 -0
  157. package/lib/ModalBindings.js +223 -0
  158. package/lib/ModalBindings.js.map +1 -0
  159. package/lib/MountBucket.d.ts +80 -0
  160. package/lib/MountBucket.d.ts.map +1 -0
  161. package/lib/MountBucket.js +44 -0
  162. package/lib/MountBucket.js.map +1 -0
  163. package/lib/MountVolume.d.ts +77 -0
  164. package/lib/MountVolume.d.ts.map +1 -0
  165. package/lib/MountVolume.js +41 -0
  166. package/lib/MountVolume.js.map +1 -0
  167. package/lib/Mounts.d.ts +134 -0
  168. package/lib/Mounts.d.ts.map +1 -0
  169. package/lib/Mounts.js +87 -0
  170. package/lib/Mounts.js.map +1 -0
  171. package/lib/PersistentSandbox.d.ts +75 -0
  172. package/lib/PersistentSandbox.d.ts.map +1 -0
  173. package/lib/PersistentSandbox.js +93 -0
  174. package/lib/PersistentSandbox.js.map +1 -0
  175. package/lib/Providers.d.ts +23 -0
  176. package/lib/Providers.d.ts.map +1 -0
  177. package/lib/Providers.js +64 -0
  178. package/lib/Providers.js.map +1 -0
  179. package/lib/Proxy.d.ts +94 -0
  180. package/lib/Proxy.d.ts.map +1 -0
  181. package/lib/Proxy.js +132 -0
  182. package/lib/Proxy.js.map +1 -0
  183. package/lib/Queue.d.ts +147 -0
  184. package/lib/Queue.d.ts.map +1 -0
  185. package/lib/Queue.js +177 -0
  186. package/lib/Queue.js.map +1 -0
  187. package/lib/QueueClient.d.ts +64 -0
  188. package/lib/QueueClient.d.ts.map +1 -0
  189. package/lib/QueueClient.js +73 -0
  190. package/lib/QueueClient.js.map +1 -0
  191. package/lib/ReadApp.d.ts +85 -0
  192. package/lib/ReadApp.d.ts.map +1 -0
  193. package/lib/ReadApp.js +3 -0
  194. package/lib/ReadApp.js.map +1 -0
  195. package/lib/ReadAppHttp.d.ts +26 -0
  196. package/lib/ReadAppHttp.d.ts.map +1 -0
  197. package/lib/ReadAppHttp.js +106 -0
  198. package/lib/ReadAppHttp.js.map +1 -0
  199. package/lib/ReadDict.d.ts +39 -0
  200. package/lib/ReadDict.d.ts.map +1 -0
  201. package/lib/ReadDict.js +3 -0
  202. package/lib/ReadDict.js.map +1 -0
  203. package/lib/ReadDictHttp.d.ts +12 -0
  204. package/lib/ReadDictHttp.d.ts.map +1 -0
  205. package/lib/ReadDictHttp.js +23 -0
  206. package/lib/ReadDictHttp.js.map +1 -0
  207. package/lib/ReadFunction.d.ts +73 -0
  208. package/lib/ReadFunction.d.ts.map +1 -0
  209. package/lib/ReadFunction.js +3 -0
  210. package/lib/ReadFunction.js.map +1 -0
  211. package/lib/ReadFunctionHttp.d.ts +25 -0
  212. package/lib/ReadFunctionHttp.d.ts.map +1 -0
  213. package/lib/ReadFunctionHttp.js +63 -0
  214. package/lib/ReadFunctionHttp.js.map +1 -0
  215. package/lib/ReadQueue.d.ts +39 -0
  216. package/lib/ReadQueue.d.ts.map +1 -0
  217. package/lib/ReadQueue.js +3 -0
  218. package/lib/ReadQueue.js.map +1 -0
  219. package/lib/ReadQueueHttp.d.ts +12 -0
  220. package/lib/ReadQueueHttp.d.ts.map +1 -0
  221. package/lib/ReadQueueHttp.js +23 -0
  222. package/lib/ReadQueueHttp.js.map +1 -0
  223. package/lib/ReadServer.d.ts +72 -0
  224. package/lib/ReadServer.d.ts.map +1 -0
  225. package/lib/ReadServer.js +3 -0
  226. package/lib/ReadServer.js.map +1 -0
  227. package/lib/ReadServerHttp.d.ts +25 -0
  228. package/lib/ReadServerHttp.d.ts.map +1 -0
  229. package/lib/ReadServerHttp.js +70 -0
  230. package/lib/ReadServerHttp.js.map +1 -0
  231. package/lib/ReadVolume.d.ts +40 -0
  232. package/lib/ReadVolume.d.ts.map +1 -0
  233. package/lib/ReadVolume.js +3 -0
  234. package/lib/ReadVolume.js.map +1 -0
  235. package/lib/ReadVolumeHttp.d.ts +12 -0
  236. package/lib/ReadVolumeHttp.d.ts.map +1 -0
  237. package/lib/ReadVolumeHttp.js +24 -0
  238. package/lib/ReadVolumeHttp.js.map +1 -0
  239. package/lib/ReadWriteDict.d.ts +39 -0
  240. package/lib/ReadWriteDict.d.ts.map +1 -0
  241. package/lib/ReadWriteDict.js +3 -0
  242. package/lib/ReadWriteDict.js.map +1 -0
  243. package/lib/ReadWriteDictHttp.d.ts +12 -0
  244. package/lib/ReadWriteDictHttp.d.ts.map +1 -0
  245. package/lib/ReadWriteDictHttp.js +23 -0
  246. package/lib/ReadWriteDictHttp.js.map +1 -0
  247. package/lib/ReadWriteQueue.d.ts +40 -0
  248. package/lib/ReadWriteQueue.d.ts.map +1 -0
  249. package/lib/ReadWriteQueue.js +3 -0
  250. package/lib/ReadWriteQueue.js.map +1 -0
  251. package/lib/ReadWriteQueueHttp.d.ts +12 -0
  252. package/lib/ReadWriteQueueHttp.d.ts.map +1 -0
  253. package/lib/ReadWriteQueueHttp.js +23 -0
  254. package/lib/ReadWriteQueueHttp.js.map +1 -0
  255. package/lib/ReadWriteVolume.d.ts +40 -0
  256. package/lib/ReadWriteVolume.d.ts.map +1 -0
  257. package/lib/ReadWriteVolume.js +3 -0
  258. package/lib/ReadWriteVolume.js.map +1 -0
  259. package/lib/ReadWriteVolumeHttp.d.ts +12 -0
  260. package/lib/ReadWriteVolumeHttp.d.ts.map +1 -0
  261. package/lib/ReadWriteVolumeHttp.js +24 -0
  262. package/lib/ReadWriteVolumeHttp.js.map +1 -0
  263. package/lib/RuntimeOwner.d.ts +39 -0
  264. package/lib/RuntimeOwner.d.ts.map +1 -0
  265. package/lib/RuntimeOwner.js +85 -0
  266. package/lib/RuntimeOwner.js.map +1 -0
  267. package/lib/Sandbox.d.ts +215 -0
  268. package/lib/Sandbox.d.ts.map +1 -0
  269. package/lib/Sandbox.js +278 -0
  270. package/lib/Sandbox.js.map +1 -0
  271. package/lib/SandboxClient.d.ts +748 -0
  272. package/lib/SandboxClient.d.ts.map +1 -0
  273. package/lib/SandboxClient.js +710 -0
  274. package/lib/SandboxClient.js.map +1 -0
  275. package/lib/ScaleFunction.d.ts +54 -0
  276. package/lib/ScaleFunction.d.ts.map +1 -0
  277. package/lib/ScaleFunction.js +3 -0
  278. package/lib/ScaleFunction.js.map +1 -0
  279. package/lib/ScaleFunctionHttp.d.ts +21 -0
  280. package/lib/ScaleFunctionHttp.d.ts.map +1 -0
  281. package/lib/ScaleFunctionHttp.js +39 -0
  282. package/lib/ScaleFunctionHttp.js.map +1 -0
  283. package/lib/Secret.d.ts +170 -0
  284. package/lib/Secret.d.ts.map +1 -0
  285. package/lib/Secret.js +196 -0
  286. package/lib/Secret.js.map +1 -0
  287. package/lib/Server.d.ts +155 -0
  288. package/lib/Server.d.ts.map +1 -0
  289. package/lib/Server.js +184 -0
  290. package/lib/Server.js.map +1 -0
  291. package/lib/ServiceUser.d.ts +139 -0
  292. package/lib/ServiceUser.d.ts.map +1 -0
  293. package/lib/ServiceUser.js +210 -0
  294. package/lib/ServiceUser.js.map +1 -0
  295. package/lib/Volume.d.ts +170 -0
  296. package/lib/Volume.d.ts.map +1 -0
  297. package/lib/Volume.js +220 -0
  298. package/lib/Volume.js.map +1 -0
  299. package/lib/VolumeClient.d.ts +53 -0
  300. package/lib/VolumeClient.d.ts.map +1 -0
  301. package/lib/VolumeClient.js +22 -0
  302. package/lib/VolumeClient.js.map +1 -0
  303. package/lib/VolumeFiles.d.ts +94 -0
  304. package/lib/VolumeFiles.d.ts.map +1 -0
  305. package/lib/VolumeFiles.js +139 -0
  306. package/lib/VolumeFiles.js.map +1 -0
  307. package/lib/WebhookToken.d.ts +102 -0
  308. package/lib/WebhookToken.d.ts.map +1 -0
  309. package/lib/WebhookToken.js +176 -0
  310. package/lib/WebhookToken.js.map +1 -0
  311. package/lib/WorkspaceSettings.d.ts +70 -0
  312. package/lib/WorkspaceSettings.d.ts.map +1 -0
  313. package/lib/WorkspaceSettings.js +105 -0
  314. package/lib/WorkspaceSettings.js.map +1 -0
  315. package/lib/WriteApp.d.ts +38 -0
  316. package/lib/WriteApp.d.ts.map +1 -0
  317. package/lib/WriteApp.js +3 -0
  318. package/lib/WriteApp.js.map +1 -0
  319. package/lib/WriteAppHttp.d.ts +23 -0
  320. package/lib/WriteAppHttp.d.ts.map +1 -0
  321. package/lib/WriteAppHttp.js +36 -0
  322. package/lib/WriteAppHttp.js.map +1 -0
  323. package/lib/WriteDict.d.ts +39 -0
  324. package/lib/WriteDict.d.ts.map +1 -0
  325. package/lib/WriteDict.js +3 -0
  326. package/lib/WriteDict.js.map +1 -0
  327. package/lib/WriteDictHttp.d.ts +12 -0
  328. package/lib/WriteDictHttp.d.ts.map +1 -0
  329. package/lib/WriteDictHttp.js +23 -0
  330. package/lib/WriteDictHttp.js.map +1 -0
  331. package/lib/WriteQueue.d.ts +39 -0
  332. package/lib/WriteQueue.d.ts.map +1 -0
  333. package/lib/WriteQueue.js +3 -0
  334. package/lib/WriteQueue.js.map +1 -0
  335. package/lib/WriteQueueHttp.d.ts +12 -0
  336. package/lib/WriteQueueHttp.d.ts.map +1 -0
  337. package/lib/WriteQueueHttp.js +23 -0
  338. package/lib/WriteQueueHttp.js.map +1 -0
  339. package/lib/WriteSecret.d.ts +53 -0
  340. package/lib/WriteSecret.d.ts.map +1 -0
  341. package/lib/WriteSecret.js +3 -0
  342. package/lib/WriteSecret.js.map +1 -0
  343. package/lib/WriteSecretHttp.d.ts +23 -0
  344. package/lib/WriteSecretHttp.d.ts.map +1 -0
  345. package/lib/WriteSecretHttp.js +44 -0
  346. package/lib/WriteSecretHttp.js.map +1 -0
  347. package/lib/WriteVolume.d.ts +39 -0
  348. package/lib/WriteVolume.d.ts.map +1 -0
  349. package/lib/WriteVolume.js +3 -0
  350. package/lib/WriteVolume.js.map +1 -0
  351. package/lib/WriteVolumeHttp.d.ts +12 -0
  352. package/lib/WriteVolumeHttp.d.ts.map +1 -0
  353. package/lib/WriteVolumeHttp.js +24 -0
  354. package/lib/WriteVolumeHttp.js.map +1 -0
  355. package/lib/index.d.ts +80 -0
  356. package/lib/index.d.ts.map +1 -0
  357. package/lib/index.js +78 -0
  358. package/lib/index.js.map +1 -0
  359. package/lib/internal/Declared.d.ts +29 -0
  360. package/lib/internal/Declared.d.ts.map +1 -0
  361. package/lib/internal/Declared.js +31 -0
  362. package/lib/internal/Declared.js.map +1 -0
  363. package/lib/internal/Deploy.d.ts +110 -0
  364. package/lib/internal/Deploy.d.ts.map +1 -0
  365. package/lib/internal/Deploy.js +230 -0
  366. package/lib/internal/Deploy.js.map +1 -0
  367. package/lib/internal/Entrypoint.d.ts +52 -0
  368. package/lib/internal/Entrypoint.d.ts.map +1 -0
  369. package/lib/internal/Entrypoint.js +193 -0
  370. package/lib/internal/Entrypoint.js.map +1 -0
  371. package/lib/internal/Rpc.d.ts +17 -0
  372. package/lib/internal/Rpc.d.ts.map +1 -0
  373. package/lib/internal/Rpc.js +49 -0
  374. package/lib/internal/Rpc.js.map +1 -0
  375. package/lib/internal/RpcAuth.d.ts +41 -0
  376. package/lib/internal/RpcAuth.d.ts.map +1 -0
  377. package/lib/internal/RpcAuth.js +100 -0
  378. package/lib/internal/RpcAuth.js.map +1 -0
  379. package/lib/internal/Runtime.d.ts +127 -0
  380. package/lib/internal/Runtime.d.ts.map +1 -0
  381. package/lib/internal/Runtime.js +246 -0
  382. package/lib/internal/Runtime.js.map +1 -0
  383. package/lib/internal/Tags.d.ts +19 -0
  384. package/lib/internal/Tags.d.ts.map +1 -0
  385. package/lib/internal/Tags.js +33 -0
  386. package/lib/internal/Tags.js.map +1 -0
  387. package/lib/internal/TcpConnect.d.ts +12 -0
  388. package/lib/internal/TcpConnect.d.ts.map +1 -0
  389. package/lib/internal/TcpConnect.js +46 -0
  390. package/lib/internal/TcpConnect.js.map +1 -0
  391. package/lib/internal/Transport.d.ts +13 -0
  392. package/lib/internal/Transport.d.ts.map +1 -0
  393. package/lib/internal/Transport.js +16 -0
  394. package/lib/internal/Transport.js.map +1 -0
  395. package/lib/internal.d.ts +71 -0
  396. package/lib/internal.d.ts.map +1 -0
  397. package/lib/internal.js +102 -0
  398. package/lib/internal.js.map +1 -0
  399. package/package.json +59 -3
  400. package/src/App.ts +262 -0
  401. package/src/AuthProvider.ts +295 -0
  402. package/src/BindingHttp.ts +112 -0
  403. package/src/Blob.ts +71 -0
  404. package/src/Bootstrap.ts +52 -0
  405. package/src/Cbor.ts +158 -0
  406. package/src/ConnectSandbox.ts +99 -0
  407. package/src/Container.ts +121 -0
  408. package/src/Contributions.ts +9 -0
  409. package/src/CreateDict.ts +95 -0
  410. package/src/CreateDictHttp.ts +91 -0
  411. package/src/CreateImage.ts +105 -0
  412. package/src/CreateImageHttp.ts +117 -0
  413. package/src/CreateQueue.ts +95 -0
  414. package/src/CreateQueueHttp.ts +91 -0
  415. package/src/CreateSandbox.ts +228 -0
  416. package/src/CreateSandboxHttp.ts +160 -0
  417. package/src/CreateSecret.ts +109 -0
  418. package/src/CreateSecretHttp.ts +83 -0
  419. package/src/CreateVolume.ts +96 -0
  420. package/src/CreateVolumeHttp.ts +93 -0
  421. package/src/Credentials.ts +74 -0
  422. package/src/Dict.ts +245 -0
  423. package/src/DictClient.ts +166 -0
  424. package/src/Domain.ts +147 -0
  425. package/src/Endpoint.ts +406 -0
  426. package/src/Environment.ts +373 -0
  427. package/src/FetchServer.ts +126 -0
  428. package/src/FetchServerHttp.ts +110 -0
  429. package/src/Function.ts +397 -0
  430. package/src/FunctionAutoscaler.ts +210 -0
  431. package/src/FunctionTarget.ts +181 -0
  432. package/src/Image.ts +281 -0
  433. package/src/ImageBuild.ts +228 -0
  434. package/src/ImagePlan.ts +78 -0
  435. package/src/InferEnv.ts +27 -0
  436. package/src/InvokeFunction.ts +211 -0
  437. package/src/InvokeFunctionHttp.ts +316 -0
  438. package/src/ModalBindings.ts +310 -0
  439. package/src/MountBucket.ts +137 -0
  440. package/src/MountVolume.ts +113 -0
  441. package/src/Mounts.ts +230 -0
  442. package/src/PersistentSandbox.ts +142 -0
  443. package/src/Providers.ts +100 -0
  444. package/src/Proxy.ts +191 -0
  445. package/src/Queue.ts +258 -0
  446. package/src/QueueClient.ts +149 -0
  447. package/src/ReadApp.ts +101 -0
  448. package/src/ReadAppHttp.ts +142 -0
  449. package/src/ReadDict.ts +44 -0
  450. package/src/ReadDictHttp.ts +27 -0
  451. package/src/ReadFunction.ts +107 -0
  452. package/src/ReadFunctionHttp.ts +91 -0
  453. package/src/ReadQueue.ts +44 -0
  454. package/src/ReadQueueHttp.ts +27 -0
  455. package/src/ReadServer.ts +98 -0
  456. package/src/ReadServerHttp.ts +101 -0
  457. package/src/ReadVolume.ts +45 -0
  458. package/src/ReadVolumeHttp.ts +28 -0
  459. package/src/ReadWriteDict.ts +44 -0
  460. package/src/ReadWriteDictHttp.ts +27 -0
  461. package/src/ReadWriteQueue.ts +45 -0
  462. package/src/ReadWriteQueueHttp.ts +27 -0
  463. package/src/ReadWriteVolume.ts +45 -0
  464. package/src/ReadWriteVolumeHttp.ts +28 -0
  465. package/src/RuntimeOwner.ts +111 -0
  466. package/src/Sandbox.ts +402 -0
  467. package/src/SandboxClient.ts +1404 -0
  468. package/src/ScaleFunction.ts +70 -0
  469. package/src/ScaleFunctionHttp.ts +54 -0
  470. package/src/Secret.ts +296 -0
  471. package/src/Server.ts +285 -0
  472. package/src/ServiceUser.ts +295 -0
  473. package/src/Volume.ts +320 -0
  474. package/src/VolumeClient.ts +108 -0
  475. package/src/VolumeFiles.ts +194 -0
  476. package/src/WebhookToken.ts +230 -0
  477. package/src/WorkspaceSettings.ts +160 -0
  478. package/src/WriteApp.ts +43 -0
  479. package/src/WriteAppHttp.ts +51 -0
  480. package/src/WriteDict.ts +44 -0
  481. package/src/WriteDictHttp.ts +27 -0
  482. package/src/WriteQueue.ts +44 -0
  483. package/src/WriteQueueHttp.ts +27 -0
  484. package/src/WriteSecret.ts +60 -0
  485. package/src/WriteSecretHttp.ts +56 -0
  486. package/src/WriteVolume.ts +44 -0
  487. package/src/WriteVolumeHttp.ts +28 -0
  488. package/src/globals.d.ts +2 -0
  489. package/src/index.ts +85 -0
  490. package/src/internal/Declared.ts +80 -0
  491. package/src/internal/Deploy.ts +309 -0
  492. package/src/internal/Entrypoint.ts +198 -0
  493. package/src/internal/Rpc.ts +59 -0
  494. package/src/internal/RpcAuth.ts +132 -0
  495. package/src/internal/Runtime.ts +386 -0
  496. package/src/internal/Tags.ts +44 -0
  497. package/src/internal/TcpConnect.ts +78 -0
  498. package/src/internal/Transport.ts +25 -0
  499. package/src/internal.ts +147 -0
@@ -0,0 +1,386 @@
1
+ import * as classes from "@distilled.cloud/modal/classes";
2
+ import * as functions from "@distilled.cloud/modal/functions";
3
+ import * as secret from "@distilled.cloud/modal/secret";
4
+ import { isResolved } from "alchemy/Diff";
5
+ import type { Input } from "alchemy/Input";
6
+ import { Stack } from "alchemy/Stack";
7
+ import { sha256Object } from "alchemy/Util/sha256";
8
+ import * as Effect from "effect/Effect";
9
+ import * as Redacted from "effect/Redacted";
10
+ import type { ContainerProps, Ref } from "../Container.ts";
11
+ import { gpuConfig } from "../ImageBuild.ts";
12
+ import { envNameOf, objectName, seconds } from "../internal.ts";
13
+ import {
14
+ boundCapabilities,
15
+ boundMounts,
16
+ type ModalMounts,
17
+ type Mount,
18
+ type MountBindings,
19
+ modalMountsOf,
20
+ } from "../Mounts.ts";
21
+ import type { Providers } from "../Providers.ts";
22
+ import { putSecret } from "../Secret.ts";
23
+ import { resolveDeclarations } from "./Declared.ts";
24
+ import {
25
+ buildRuntimeImage,
26
+ classTag,
27
+ clientMount,
28
+ DEFAULT_PORT,
29
+ entrypointMount,
30
+ ModalDeployUnexpectedResponse,
31
+ planRuntimeImage,
32
+ publishFunction,
33
+ } from "./Deploy.ts";
34
+ import { ENTRYPOINT_MODULE } from "./Entrypoint.ts";
35
+ import { RPC_CALLERS_ENV, type RpcCallerBinding, rpcCallersOf } from "./RpcAuth.ts";
36
+
37
+ /** What a runtime's bindings attach: mounts, and the keys of RPC callers. */
38
+ type RuntimeBindings = ReadonlyArray<{
39
+ readonly data: { readonly mounts?: MountBindings[number]["data"]["mounts"] } & RpcCallerBinding;
40
+ }>;
41
+
42
+ /** Attributes shared by `Modal.Function` and `Modal.Server`. */
43
+ export interface RuntimeAttributes {
44
+ /** Function ID (`fu-…`). */
45
+ functionId: string;
46
+ /** Name of the function in its App. */
47
+ name: string;
48
+ /** The App the function is deployed in. */
49
+ appId: string;
50
+ /** Name of that App. */
51
+ appName: string | undefined;
52
+ /** Environment of that App. */
53
+ environment: string | undefined;
54
+ /** The image with the bundled program (`im-…`). */
55
+ imageId: string;
56
+ /** The Modal Secret holding the program's env (bindings' credentials included). */
57
+ secretId: string;
58
+ /** Name of that secret. */
59
+ secretName: string;
60
+ /** Port the program listens on. */
61
+ port: number;
62
+ /** The command the entrypoint starts. */
63
+ command: string[];
64
+ /** Content hash of the bundle, image and function definition. */
65
+ hash: string;
66
+ /** The class (`cs-…`) of a function with RPC methods, which Modal runs as a class. */
67
+ classId?: string | undefined;
68
+ }
69
+
70
+ /** What differs between a Function and a Server. */
71
+ export interface RuntimeKind<P extends ContainerProps> {
72
+ /** Resource type, e.g. `Modal.Function`. */
73
+ readonly type: string;
74
+ /** The Function fields specific to the kind (webhook, schedule, HTTP config, ...). */
75
+ readonly definition: (
76
+ props: P,
77
+ context: { readonly port: number; readonly startupTimeout: number },
78
+ ) => functions.Function;
79
+ /** The program's bootstrap for an Effect-native `main`. */
80
+ readonly bootstrap: (handler: string) => (importPath: string) => string;
81
+ /** Env the kind adds to the program's (e.g. turning RPC on). */
82
+ readonly env?: (props: P) => Record<string, string>;
83
+ }
84
+
85
+ const resolveRef = <T>(value: Ref<T>) =>
86
+ Effect.isEffect(value) ? (value as Effect.Effect<T, never, Providers>) : Effect.succeed(value);
87
+
88
+ /**
89
+ * `{ app: Coder, mounts: [{ volume: Data, path: "/data" }] }` at module scope
90
+ * holds Effects: yield them so the resources are registered and the props
91
+ * hold their resolved attributes at reconcile.
92
+ */
93
+ export const resolveContainerProps = <P extends ContainerProps>(_id: string, props: P) =>
94
+ Effect.gen(function* () {
95
+ if (globalThis.__ALCHEMY_RUNTIME__) return props;
96
+ const app = yield* resolveRef(props.app);
97
+ const proxy = props.proxy === undefined ? undefined : yield* resolveRef(props.proxy);
98
+ const secrets =
99
+ props.secrets === undefined ? undefined : yield* Effect.forEach(props.secrets, resolveRef);
100
+ const mounts =
101
+ props.mounts === undefined
102
+ ? undefined
103
+ : ((yield* resolveDeclarations(props.mounts)) as Mount[]);
104
+ return { ...props, app, proxy, secrets, mounts };
105
+ });
106
+
107
+ /** The resolved app of the props. */
108
+ export const appOf = (value: unknown) => {
109
+ const rec = (value ?? {}) as { appId?: string; name?: string; environment?: unknown };
110
+ return { appId: rec.appId ?? "", appName: rec.name, environment: envNameOf(rec.environment) };
111
+ };
112
+
113
+ const idOf = (value: unknown, key: string): string | undefined =>
114
+ typeof value === "object" && value !== null && key in value
115
+ ? ((value as Record<string, unknown>)[key] as string | undefined)
116
+ : undefined;
117
+
118
+ /** An env value as a string, as the program's `process.env` sees it. */
119
+ const envText = (value: unknown): string =>
120
+ typeof value === "string"
121
+ ? value
122
+ : Redacted.isRedacted(value)
123
+ ? String(Redacted.value(value))
124
+ : JSON.stringify(value ?? null);
125
+
126
+ /** The function definition fields every kind shares. */
127
+ const baseDefinition = (
128
+ props: ContainerProps,
129
+ context: {
130
+ readonly tag: string;
131
+ readonly appName: string | undefined;
132
+ readonly timeout: number;
133
+ readonly startupTimeout: number;
134
+ },
135
+ mounts: ModalMounts,
136
+ ): functions.Function => ({
137
+ moduleName: ENTRYPOINT_MODULE,
138
+ functionName: context.tag,
139
+ definitionType: "DEFINITION_TYPE_FILE",
140
+ functionType: "FUNCTION_TYPE_FUNCTION",
141
+ resources: {
142
+ milliCpu: props.cpu !== undefined ? Math.round(props.cpu * 1000) : undefined,
143
+ milliCpuMax: props.cpuLimit !== undefined ? Math.round(props.cpuLimit * 1000) : undefined,
144
+ memoryMb: props.memory,
145
+ memoryMbMax: props.memoryLimit,
146
+ gpuConfig: gpuConfig(props.gpu),
147
+ ephemeralDiskMb: props.ephemeralDisk,
148
+ },
149
+ volumeMounts: mounts.volumeMounts,
150
+ cloudBucketMounts: mounts.cloudBucketMounts,
151
+ proxyId: idOf(props.proxy, "proxyId"),
152
+ timeoutSecs: Math.round(context.timeout),
153
+ startupTimeoutSecs: Math.round(context.startupTimeout),
154
+ cloudProviderStr: props.cloud ?? "",
155
+ appName: context.appName ?? "",
156
+ schedulerPlacement:
157
+ props.regions !== undefined || props.nonpreemptible
158
+ ? { regions: props.regions, nonpreemptible: props.nonpreemptible }
159
+ : undefined,
160
+ autoscalerSettings: {
161
+ minContainers: props.minContainers,
162
+ maxContainers: props.maxContainers,
163
+ bufferContainers: props.bufferContainers,
164
+ scaleupWindow: props.scaleupWindow,
165
+ scaledownWindow: props.scaledownWindow,
166
+ },
167
+ // Older mirrors of `autoscalerSettings` the Python client still sets.
168
+ warmPoolSize: props.minContainers ?? 0,
169
+ concurrencyLimit: props.maxContainers ?? 0,
170
+ ExperimentalBufferContainers: props.bufferContainers ?? 0,
171
+ taskIdleTimeoutSecs: props.scaledownWindow ?? 0,
172
+ checkpointingEnabled: props.enableMemorySnapshot,
173
+ blockNetwork: props.blockNetwork,
174
+ untrusted: props.restrictModalAccess,
175
+ i6pnEnabled: props.i6pn,
176
+ methodDefinitionsSet: true,
177
+ mountClientDependencies: true,
178
+ ExperimentalConcurrentCancellations: true,
179
+ });
180
+
181
+ /**
182
+ * The lifecycle shared by every Modal runtime: a function in an App whose
183
+ * container runs the bundled program behind Alchemy's Python entrypoint.
184
+ *
185
+ * 1. the program's env goes into a Modal Secret (values never enter the image);
186
+ * 2. the image is the base plus standalone Python plus the bundle, built by
187
+ * Modal and reused while its inputs don't change;
188
+ * 3. `FunctionCreate` writes the definition (with the entrypoint and client
189
+ * mounts), updating the existing function in place;
190
+ * 4. the App is republished with the function, keeping its other functions.
191
+ */
192
+ export const runtimeLifecycle = <P extends ContainerProps>(kind: RuntimeKind<P>) =>
193
+ Effect.gen(function* () {
194
+ const stack = yield* Stack;
195
+
196
+ const prepare = Effect.fn(function* (id: string, news: P, bindings: RuntimeBindings) {
197
+ const port = news.port ?? DEFAULT_PORT;
198
+ const tag = news.name ?? id;
199
+ const app = appOf(news.app);
200
+ const timeout = seconds(news.timeout) ?? 300;
201
+ const startupTimeout = seconds(news.startupTimeout) ?? timeout;
202
+ const image = yield* planRuntimeImage(
203
+ kind.type,
204
+ news,
205
+ port,
206
+ news.isExternal ? undefined : kind.bootstrap(news.handler ?? "default"),
207
+ boundCapabilities(bindings),
208
+ );
209
+ // The props' mounts, then the ones `Modal.MountVolume` / `MountBucket` bound.
210
+ const mounts = yield* modalMountsOf([...(news.mounts ?? []), ...boundMounts(bindings)]);
211
+ const base = baseDefinition(
212
+ news,
213
+ { tag, appName: app.appName, timeout, startupTimeout },
214
+ mounts,
215
+ );
216
+ const specific = kind.definition(news, { port, startupTimeout });
217
+ const definition: functions.Function = {
218
+ ...base,
219
+ ...specific,
220
+ // A class's service function is named `<tag>.*`, as Modal's clients name it.
221
+ functionName: specific.isClass ? classTag(tag) : tag,
222
+ autoscalerSettings: { ...base.autoscalerSettings, ...specific.autoscalerSettings },
223
+ };
224
+ const secretIds = (news.secrets ?? []).flatMap((s) => idOf(s, "secretId") ?? []);
225
+ const env = {
226
+ ...Object.fromEntries(
227
+ Object.entries(news.env ?? {}).map(([key, value]) => [key, envText(value)]),
228
+ ),
229
+ ...kind.env?.(news),
230
+ // The callers whose keys open the program's RPC methods.
231
+ ...(rpcCallersOf(bindings).length > 0
232
+ ? { [RPC_CALLERS_ENV]: JSON.stringify(rpcCallersOf(bindings)) }
233
+ : {}),
234
+ };
235
+ const hash = yield* sha256Object({ image: image.hash, definition, secretIds, env });
236
+ return { port, tag, app, image, definition, secretIds, env, hash };
237
+ });
238
+
239
+ return {
240
+ stables: ["appId", "name", "secretName"] as Array<keyof RuntimeAttributes>,
241
+ diff: Effect.fn(function* ({
242
+ id,
243
+ news,
244
+ output,
245
+ newBindings,
246
+ }: {
247
+ id: string;
248
+ news: Input<P>;
249
+ output: RuntimeAttributes | undefined;
250
+ newBindings: Input<RuntimeBindings>;
251
+ }) {
252
+ if (!isResolved(news) || !isResolved(newBindings) || output === undefined) {
253
+ return undefined;
254
+ }
255
+ if (appOf(news.app).appId !== output.appId) return { action: "replace" } as const;
256
+ if ((news.name ?? id) !== output.name) return { action: "replace" } as const;
257
+ const { hash } = yield* prepare(id, news, newBindings);
258
+ return hash !== output.hash ? ({ action: "update" } as const) : undefined;
259
+ }),
260
+ read: Effect.fn(function* ({ output }: { output: RuntimeAttributes | undefined }) {
261
+ if (output === undefined) return undefined;
262
+ const found = yield* functions
263
+ .functionGetById({ functionId: output.functionId })
264
+ .pipe(Effect.catchTag("FunctionNotFound", () => Effect.undefined));
265
+ return found?.function ? output : undefined;
266
+ }),
267
+ reconcile: Effect.fn(function* ({
268
+ id,
269
+ news,
270
+ output,
271
+ session,
272
+ bindings,
273
+ }: {
274
+ id: string;
275
+ news: P;
276
+ output: RuntimeAttributes | undefined;
277
+ session: { note: (message: string) => Effect.Effect<void> };
278
+ bindings: RuntimeBindings;
279
+ }) {
280
+ const {
281
+ port,
282
+ tag,
283
+ app,
284
+ image,
285
+ definition,
286
+ secretIds,
287
+ env: programEnv,
288
+ hash,
289
+ } = yield* prepare(id, news, bindings);
290
+ for (const warning of image.warnings) yield* session.note(warning);
291
+ const secretName = output?.secretName ?? `${yield* objectName(id, undefined, 58)}-env`;
292
+
293
+ // Sync the program's env (bindings' credentials included) into the
294
+ // secret the function attaches; values never enter the image.
295
+ const env: Record<string, string> = {
296
+ ALCHEMY_STACK_NAME: stack.name,
297
+ ALCHEMY_STAGE: stack.stage,
298
+ ALCHEMY_PHASE: "runtime",
299
+ ALCHEMY_COMMAND: JSON.stringify(image.command),
300
+ HOST: "0.0.0.0",
301
+ PORT: String(port),
302
+ };
303
+ Object.assign(env, programEnv);
304
+ const stored = yield* putSecret(
305
+ yield* secret.secretGetOrCreate,
306
+ secretName,
307
+ app.environment,
308
+ env,
309
+ );
310
+
311
+ // Ensure the image: Modal reuses a cached build for the same inputs.
312
+ const imageId =
313
+ output !== undefined && output.hash === hash && output.appId === app.appId
314
+ ? output.imageId
315
+ : yield* buildRuntimeImage(app.appId, image, {
316
+ builderVersion: news.builderVersion,
317
+ gpu: news.gpu,
318
+ note: session.note,
319
+ });
320
+
321
+ const mountIds = [yield* clientMount, yield* entrypointMount(app.appId)];
322
+ yield* session.note(`Deploying ${kind.type} ${tag}...`);
323
+ const created = yield* functions.createFunction({
324
+ appId: app.appId,
325
+ function: {
326
+ ...definition,
327
+ imageId,
328
+ mountIds,
329
+ secretIds: [stored.secretId, ...secretIds],
330
+ },
331
+ existingFunctionId: output?.appId === app.appId ? output.functionId : undefined,
332
+ });
333
+ if (!created.functionId) {
334
+ return yield* new ModalDeployUnexpectedResponse({
335
+ message: `Modal returned no id for function ${tag}`,
336
+ });
337
+ }
338
+ for (const warning of created.serverWarnings ?? []) {
339
+ if (warning.message) yield* session.note(warning.message);
340
+ }
341
+ // A class function needs its class: its containers hydrate it from
342
+ // the App layout, under the function's name.
343
+ const classId = definition.isClass
344
+ ? (yield* classes.createClass({
345
+ appId: app.appId,
346
+ existingClassId: output?.appId === app.appId ? output.classId : undefined,
347
+ onlyClassFunction: true,
348
+ })).classId
349
+ : undefined;
350
+ yield* publishFunction(app, tag, {
351
+ functionId: created.functionId,
352
+ definitionId: created.handleMetadata?.definitionId,
353
+ classId,
354
+ });
355
+ return {
356
+ attributes: {
357
+ functionId: created.functionId,
358
+ name: tag,
359
+ appId: app.appId,
360
+ appName: app.appName,
361
+ environment: app.environment,
362
+ imageId,
363
+ secretId: stored.secretId,
364
+ secretName,
365
+ port,
366
+ command: image.command,
367
+ hash,
368
+ classId,
369
+ } satisfies RuntimeAttributes,
370
+ metadata: created.handleMetadata,
371
+ };
372
+ }),
373
+ delete: Effect.fn(function* ({ output }: { output: RuntimeAttributes }) {
374
+ // Republish the App without the function; stopping the App (its own
375
+ // resource) is what removes everything else.
376
+ yield* publishFunction(output, output.name, undefined).pipe(
377
+ Effect.catchTag("AppNotFound", () => Effect.void),
378
+ );
379
+ yield* secret
380
+ .deleteSecret({ secretId: output.secretId })
381
+ .pipe(Effect.catchTag("SecretNotFound", () => Effect.void));
382
+ // The image stays: Modal content-addresses builds, so another
383
+ // function or sandbox may boot from the same image id.
384
+ }),
385
+ };
386
+ });
@@ -0,0 +1,44 @@
1
+ import { createInternalTags, hasTags, type Tags } from "alchemy/Tags";
2
+ import * as Effect from "effect/Effect";
3
+
4
+ /**
5
+ * Modal tag keys and values must match `^[a-zA-Z0-9._-]{1,63}$`, so
6
+ * Alchemy's `alchemy::stack` / `alchemy::stage` / `alchemy::id` ownership
7
+ * tags are stored as `alchemy.stack` / `alchemy.stage` / `alchemy.id`, and
8
+ * their values are rewritten into that character set (`/` in a nested
9
+ * logical ID becomes `__`).
10
+ */
11
+ export const ALCHEMY_TAG_PREFIX = "alchemy.";
12
+
13
+ const INTERNAL_PREFIX = "alchemy::";
14
+
15
+ const toModalKey = (key: string): string =>
16
+ key.startsWith(INTERNAL_PREFIX)
17
+ ? `${ALCHEMY_TAG_PREFIX}${key.slice(INTERNAL_PREFIX.length)}`
18
+ : key;
19
+
20
+ const toModalValue = (value: string): string => {
21
+ const cleaned = value
22
+ .replaceAll("/", "__")
23
+ .replace(/[^A-Za-z0-9._-]/g, "-")
24
+ .slice(0, 63);
25
+ return cleaned.length > 0 ? cleaned : "-";
26
+ };
27
+
28
+ /** Alchemy's ownership tags in Modal's tag format. */
29
+ export const createModalInternalTags = Effect.fn(function* (id: string) {
30
+ const tags = yield* createInternalTags(id);
31
+ return Object.fromEntries(
32
+ Object.entries(tags).map(([key, value]) => [toModalKey(key), toModalValue(value)]),
33
+ );
34
+ });
35
+
36
+ /** Whether observed Modal tags carry this resource's ownership tags. */
37
+ export const hasModalAlchemyTags = Effect.fn(function* (id: string, tags: Tags | undefined) {
38
+ return hasTags(yield* createModalInternalTags(id), tags);
39
+ });
40
+
41
+ /** Whether observed Modal tags carry any Alchemy ownership tag. */
42
+ export const isAlchemyTagged = (
43
+ tags: Readonly<Record<string, string | undefined>> | undefined,
44
+ ): boolean => Object.keys(tags ?? {}).some((key) => key.startsWith(ALCHEMY_TAG_PREFIX));
@@ -0,0 +1,78 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Socket from "effect/socket/Socket";
3
+ import { isWorkerd } from "./Transport.ts";
4
+
5
+ /** The part of `cloudflare:sockets` this module uses. */
6
+ type CloudflareConnect = (
7
+ address: { hostname: string; port: number },
8
+ options: { secureTransport: "on" | "off"; allowHalfOpen: boolean },
9
+ ) => {
10
+ readonly readable: ReadableStream<Uint8Array>;
11
+ readonly writable: WritableStream<Uint8Array>;
12
+ close(): Promise<void>;
13
+ };
14
+
15
+ /** The parts of `node:net`, `node:tls` and `node:stream` this module uses. */
16
+ interface NodeDuplex {
17
+ destroy(): void;
18
+ }
19
+ type NodeConnect = (options: { host: string; port: number; servername?: string }) => NodeDuplex;
20
+ interface NodeStreamModule {
21
+ readonly Duplex: {
22
+ toWeb(duplex: NodeDuplex): Socket.InputTransformStream;
23
+ };
24
+ }
25
+
26
+ // Non-literal specifiers keep a bundler from pulling one runtime's sockets
27
+ // into the other's bundle: workerd resolves `cloudflare:sockets` at runtime,
28
+ // and Node resolves its built-ins.
29
+ const CLOUDFLARE_SOCKETS = "cloudflare:sockets";
30
+ const NODE_NET = "node:net";
31
+ const NODE_TLS = "node:tls";
32
+ const NODE_STREAM = "node:stream";
33
+
34
+ const importModule = <A>(specifier: string) =>
35
+ Effect.tryPromise({
36
+ try: () => import(/* @vite-ignore */ specifier) as Promise<A>,
37
+ catch: (cause) =>
38
+ Socket.SocketError.make({ reason: Socket.SocketOpenError.make({ kind: "Unknown", cause }) }),
39
+ });
40
+
41
+ const openCloudflare = (host: string, port: number, tls: boolean) =>
42
+ Effect.acquireRelease(
43
+ Effect.map(importModule<{ connect: CloudflareConnect }>(CLOUDFLARE_SOCKETS), ({ connect }) =>
44
+ connect(
45
+ { hostname: host, port },
46
+ { secureTransport: tls ? "on" : "off", allowHalfOpen: false },
47
+ ),
48
+ ),
49
+ (socket) => Effect.promise(() => socket.close().catch(() => undefined)),
50
+ );
51
+
52
+ const openNode = (host: string, port: number, tls: boolean) =>
53
+ Effect.acquireRelease(
54
+ Effect.gen(function* () {
55
+ const { Duplex } = yield* importModule<NodeStreamModule>(NODE_STREAM);
56
+ const { connect } = yield* importModule<{ connect: NodeConnect }>(tls ? NODE_TLS : NODE_NET);
57
+ const duplex = connect(tls ? { host, port, servername: host } : { host, port });
58
+ return { duplex, stream: Duplex.toWeb(duplex) };
59
+ }),
60
+ ({ duplex }) => Effect.sync(() => duplex.destroy()),
61
+ ).pipe(Effect.map(({ stream }) => stream));
62
+
63
+ /**
64
+ * A TCP socket to `host:port`, over TLS when `tls` is set: `cloudflare:sockets`
65
+ * on workerd, Node's `net`/`tls` elsewhere. It connects when run.
66
+ */
67
+ export const connectTcp = (options: {
68
+ readonly host: string;
69
+ readonly port: number;
70
+ readonly tls: boolean;
71
+ }): Effect.Effect<Socket.Socket> =>
72
+ Socket.fromTransformStream(
73
+ Effect.suspend(() =>
74
+ isWorkerd()
75
+ ? openCloudflare(options.host, options.port, options.tls)
76
+ : openNode(options.host, options.port, options.tls),
77
+ ),
78
+ );
@@ -0,0 +1,25 @@
1
+ import { GrpcTransport } from "@distilled.cloud/core/grpc-transport";
2
+ import * as CloudflareSockets from "@distilled.cloud/core/grpc-transport-cloudflare-sockets";
3
+ import * as Effect from "effect/Effect";
4
+ import * as FetchHttpClient from "effect/http/FetchHttpClient";
5
+ import type * as HttpClient from "effect/http/HttpClient";
6
+ import * as Layer from "effect/Layer";
7
+
8
+ /** Whether this code runs on workerd (a Cloudflare Worker or Durable Object). */
9
+ export const isWorkerd = (): boolean =>
10
+ typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers";
11
+
12
+ /**
13
+ * How Modal calls leave this runtime: `fetch`, and on a Cloudflare Worker,
14
+ * distilled's `cloudflare:sockets` gRPC transport. `api.modal.com` is behind
15
+ * Cloudflare, and a Worker's `fetch` to it takes Cloudflare's internal
16
+ * Worker-to-site path, which resets Modal's gRPC upstream (`grpc-status: 14`).
17
+ * Other HTTP calls (blob uploads, the user's own endpoints) keep `fetch`.
18
+ */
19
+ export const ModalTransport: Layer.Layer<HttpClient.HttpClient> = Layer.mergeAll(
20
+ FetchHttpClient.layer,
21
+ Layer.effect(
22
+ GrpcTransport,
23
+ Effect.sync(() => (isWorkerd() ? CloudflareSockets.client : undefined)),
24
+ ),
25
+ );
@@ -0,0 +1,147 @@
1
+ import type { Credentials } from "@distilled.cloud/modal/Credentials";
2
+ import * as environment from "@distilled.cloud/modal/environment";
3
+ import type { ListPagination } from "@distilled.cloud/modal/volume";
4
+ import { createPhysicalName } from "alchemy/PhysicalName";
5
+ import * as Effect from "effect/Effect";
6
+ import type * as HttpClient from "effect/http/HttpClient";
7
+
8
+ /**
9
+ * Modal object names: letters, digits, `-`, `.` and `_`, shorter than 64
10
+ * characters. Names are unique per environment and kind.
11
+ */
12
+ export const objectName = (id: string, name: string | undefined, maxLength = 63) =>
13
+ name !== undefined ? Effect.succeed(name) : createPhysicalName({ id, maxLength, delimiter: "-" });
14
+
15
+ /**
16
+ * The environment a Modal call targets. Modal resolves an empty name to the
17
+ * workspace's default environment, so `undefined` stays `""` on the wire and
18
+ * `undefined` in attributes.
19
+ */
20
+ export const environmentOf = (name: string | undefined): string => name ?? "";
21
+
22
+ /** Seconds of a duration given as seconds or a `"10 minutes"`-style string. */
23
+ export const seconds = (value: number | string | undefined): number | undefined => {
24
+ if (value === undefined) return undefined;
25
+ if (typeof value === "number") return value;
26
+ const match =
27
+ /^\s*(\d+(?:\.\d+)?)\s*(ms|millis|milliseconds?|s|secs?|seconds?|m|mins?|minutes?|h|hours?)\s*$/i.exec(
28
+ value,
29
+ );
30
+ if (!match) return Number(value);
31
+ const n = Number(match[1]);
32
+ const unit = match[2]!.toLowerCase();
33
+ if (unit.startsWith("ms") || unit.startsWith("milli")) return n / 1000;
34
+ if (unit.startsWith("h")) return n * 3600;
35
+ if (unit.startsWith("m")) return n * 60;
36
+ return n;
37
+ };
38
+
39
+ /**
40
+ * Every item of a Modal `List*` call. Modal pages by creation time: each
41
+ * request takes `maxObjects` and `createdBefore`, the creation time of the
42
+ * oldest item seen so far.
43
+ */
44
+ export const listAll: <T, E, R>(
45
+ fetch: (pagination: ListPagination) => Effect.Effect<ReadonlyArray<T>, E, R>,
46
+ createdAt: (item: T) => number | undefined,
47
+ pageSize?: number,
48
+ ) => Effect.Effect<T[], E, R> = Effect.fn(function* <T, E, R>(
49
+ fetch: (pagination: ListPagination) => Effect.Effect<ReadonlyArray<T>, E, R>,
50
+ createdAt: (item: T) => number | undefined,
51
+ pageSize = 100,
52
+ ) {
53
+ const all: T[] = [];
54
+ let before: number | undefined;
55
+ for (let page = 0; page < 1_000; page++) {
56
+ const items = yield* fetch({ maxObjects: pageSize, createdBefore: before });
57
+ all.push(...items);
58
+ if (items.length < pageSize) break;
59
+ const oldest = Math.min(...items.map((item) => createdAt(item) ?? Number.POSITIVE_INFINITY));
60
+ if (!Number.isFinite(oldest) || oldest === before) break;
61
+ before = oldest;
62
+ }
63
+ return all;
64
+ });
65
+
66
+ /**
67
+ * The names of every environment in the workspace, for `list` operations that
68
+ * enumerate objects across environments.
69
+ */
70
+ export const environmentNames = Effect.gen(function* () {
71
+ const response = yield* environment.listEnvironment({});
72
+ return (response.items ?? []).flatMap((item) => (item.name ? [item.name] : []));
73
+ });
74
+
75
+ /** A wire `map<string, string>` without the absent entries proto3 JSON allows. */
76
+ export const stringMap = (
77
+ map: Readonly<Record<string, string | undefined>> | undefined,
78
+ ): Record<string, string> =>
79
+ Object.fromEntries(
80
+ Object.entries(map ?? {}).flatMap(([key, value]) =>
81
+ value === undefined ? [] : [[key, value]],
82
+ ),
83
+ );
84
+
85
+ /**
86
+ * Whether a name was generated by `createPhysicalName` (it ends in a
87
+ * 16-character base32 instance suffix, or an 8-character truncation hash plus
88
+ * the suffix). Modal objects other than Apps and Sandboxes have no tags, so
89
+ * `list` (and `alchemy nuke`) only enumerate objects with generated names
90
+ * and the objects runtimes created (`isRuntimeName`); objects given an
91
+ * explicit `name` are never swept.
92
+ */
93
+ export const isGeneratedName = (name: string | undefined): boolean =>
94
+ name !== undefined && /-[a-z2-7]{16}$/.test(name);
95
+
96
+ /**
97
+ * An environment by name, or a `Modal.Environment` (yielded: `yield* Agents`)
98
+ * whose name is used.
99
+ */
100
+ export type EnvironmentInput = string | { readonly name: string };
101
+
102
+ /** The environment name an {@link EnvironmentInput} resolved to. */
103
+ export const envNameOf = (value: unknown): string | undefined =>
104
+ typeof value === "string"
105
+ ? value || undefined
106
+ : typeof value === "object" &&
107
+ value !== null &&
108
+ "name" in value &&
109
+ typeof value.name === "string"
110
+ ? value.name
111
+ : undefined;
112
+
113
+ /** A protobuf `Timestamp` (RFC 3339) for a `Date`, ISO string or epoch milliseconds. */
114
+ export const timestampOf = (value: Date | string | number): string =>
115
+ typeof value === "string" ? value : new Date(value).toISOString();
116
+
117
+ /**
118
+ * Resolve a record of distilled operations into their call functions, like
119
+ * `Effect.all` over Effects. An operation is yieldable (`yield* op` captures
120
+ * the current context and returns a requirement-free call) but isn't an
121
+ * Effect value at runtime, so `Effect.all({ put: queue.putQueue })` fails.
122
+ *
123
+ * @example
124
+ * ```ts
125
+ * const QueueOps = operations({ put: queue.putQueue, get: queue.getQueue });
126
+ * const { put } = yield* ModalBindings.withCredentials(QueueOps);
127
+ * ```
128
+ */
129
+ export const operations = <
130
+ const Ops extends Record<string, Effect.Effect<unknown, never, OperationServices>>,
131
+ >(
132
+ ops: Ops,
133
+ ): Effect.Effect<{ readonly [K in keyof Ops]: Effect.Success<Ops[K]> }, never, OperationServices> =>
134
+ Effect.gen(function* () {
135
+ const resolved: Record<string, unknown> = {};
136
+ for (const [key, op] of Object.entries(ops)) resolved[key] = yield* op;
137
+ return resolved as { readonly [K in keyof Ops]: Effect.Success<Ops[K]> };
138
+ });
139
+
140
+ /** The error of a resolved distilled call (or any function returning an Effect). */
141
+ export type ErrorOf<F> = F extends (...args: any[]) => Effect.Effect<any, infer E, any> ? E : never;
142
+
143
+ /** The error of operation `K` of a resolved operations record. */
144
+ export type OpError<Ops, K extends keyof Ops> = ErrorOf<Ops[K]>;
145
+
146
+ /** What a distilled Modal operation needs to run: credentials and an HTTP client. */
147
+ export type OperationServices = Credentials | HttpClient.HttpClient;