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

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,45 @@
1
+ import * as Binding from "alchemy/Binding";
2
+ import type * as Effect from "effect/Effect";
3
+ import type { Queue } from "./Queue.ts";
4
+ import type { ReadWriteQueueClient } from "./QueueClient.ts";
5
+
6
+ export type { ReadWriteQueueClient } from "./QueueClient.ts";
7
+
8
+ /**
9
+ * Put and take items on a Modal Queue from any runtime. Items are JSON.
10
+ *
11
+ * ### Bind a queue
12
+ * **Example:** From a Cloudflare Worker
13
+ * ```typescript
14
+ * import * as Cloudflare from "@alchemy.run/cloudflare";
15
+ * import * as Modal from "@alchemy.run/modal";
16
+ * import * as Effect from "effect/Effect";
17
+ * import * as HttpServerResponse from "effect/http/HttpServerResponse";
18
+ * import { Jobs } from "./Storage.ts";
19
+ *
20
+ * export default class Api extends Cloudflare.Worker<Api>()(
21
+ * "Api",
22
+ * { main: import.meta.url },
23
+ * Effect.gen(function* () {
24
+ * const queue = yield* Modal.ReadWriteQueue(Jobs);
25
+ * return {
26
+ * fetch: Effect.gen(function* () {
27
+ * yield* queue.put({ n: 1 });
28
+ * const items = yield* queue.take({ count: 10 });
29
+ * return yield* HttpServerResponse.json(items);
30
+ * }).pipe(Effect.orDie),
31
+ * };
32
+ * }).pipe(Effect.provide(Modal.ReadWriteQueueHttp)),
33
+ * ) {}
34
+ * ```
35
+ *
36
+ * @binding
37
+ * @product Queue
38
+ */
39
+ export interface ReadWriteQueue extends Binding.Service<
40
+ ReadWriteQueue,
41
+ "Modal.ReadWriteQueue",
42
+ (queue: Queue) => Effect.Effect<ReadWriteQueueClient>
43
+ > {}
44
+
45
+ export const ReadWriteQueue = Binding.Service<ReadWriteQueue>("Modal.ReadWriteQueue");
@@ -0,0 +1,27 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Layer from "effect/Layer";
3
+ import { makeModalBinding } from "./BindingHttp.ts";
4
+ import type { Queue } from "./Queue.ts";
5
+ import { QueueOps, makeReadWriteQueueClient } from "./QueueClient.ts";
6
+ import { ReadWriteQueue } from "./ReadWriteQueue.ts";
7
+
8
+ /**
9
+ * {@link ReadWriteQueue} over Modal's API. Grants the host's identity (a scoped
10
+ * `Modal.ServiceUser`) the `contributor` role on the queue's environment.
11
+ *
12
+ * @layer
13
+ * @product Queue
14
+ * @provides Modal.ReadWriteQueue
15
+ */
16
+ export const ReadWriteQueueHttp = Layer.effect(
17
+ ReadWriteQueue,
18
+ makeModalBinding({
19
+ tag: "Modal.ReadWriteQueue",
20
+ operations: QueueOps,
21
+ role: "contributor",
22
+ make: Effect.fn(function* (queue: Queue, ops) {
23
+ const queueId = yield* queue.queueId;
24
+ return makeReadWriteQueueClient(queueId, ops);
25
+ }),
26
+ }),
27
+ );
@@ -0,0 +1,45 @@
1
+ import * as Binding from "alchemy/Binding";
2
+ import type * as Effect from "effect/Effect";
3
+ import type { Volume } from "./Volume.ts";
4
+ import type { ReadWriteVolumeClient } from "./VolumeClient.ts";
5
+
6
+ export type { ReadWriteVolumeClient } from "./VolumeClient.ts";
7
+
8
+ /**
9
+ * Read and write a Modal Volume's files from any runtime without mounting it.
10
+ *
11
+ * ### Bind a volume
12
+ * **Example:** ReadWrite from a Cloudflare Worker
13
+ * ```typescript
14
+ * import * as Cloudflare from "@alchemy.run/cloudflare";
15
+ * import * as Modal from "@alchemy.run/modal";
16
+ * import * as Effect from "effect/Effect";
17
+ * import * as HttpServerResponse from "effect/http/HttpServerResponse";
18
+ * import { Workspace } from "./Storage.ts";
19
+ *
20
+ * export default class Api extends Cloudflare.Worker<Api>()(
21
+ * "Api",
22
+ * { main: import.meta.url },
23
+ * Effect.gen(function* () {
24
+ * const volume = yield* Modal.ReadWriteVolume(Workspace);
25
+ * return {
26
+ * fetch: Effect.gen(function* () {
27
+ * yield* volume.writeFile("/hello.txt", "hello");
28
+ * const text = yield* volume.readFileString("/hello.txt");
29
+ * return HttpServerResponse.text(text);
30
+ * }).pipe(Effect.orDie),
31
+ * };
32
+ * }).pipe(Effect.provide(Modal.ReadWriteVolumeHttp)),
33
+ * ) {}
34
+ * ```
35
+ *
36
+ * @binding
37
+ * @product Volume
38
+ */
39
+ export interface ReadWriteVolume extends Binding.Service<
40
+ ReadWriteVolume,
41
+ "Modal.ReadWriteVolume",
42
+ (volume: Volume) => Effect.Effect<ReadWriteVolumeClient>
43
+ > {}
44
+
45
+ export const ReadWriteVolume = Binding.Service<ReadWriteVolume>("Modal.ReadWriteVolume");
@@ -0,0 +1,28 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Layer from "effect/Layer";
3
+ import { makeModalBinding } from "./BindingHttp.ts";
4
+ import { ReadWriteVolume } from "./ReadWriteVolume.ts";
5
+ import type { Volume } from "./Volume.ts";
6
+ import { makeReadWriteVolumeClient } from "./VolumeClient.ts";
7
+ import { VolumeFileOps } from "./VolumeFiles.ts";
8
+
9
+ /**
10
+ * {@link ReadWriteVolume} over Modal's volume API. Grants the host's identity (a scoped
11
+ * `Modal.ServiceUser`) the `contributor` role on the volume's environment.
12
+ *
13
+ * @layer
14
+ * @product Volume
15
+ * @provides Modal.ReadWriteVolume
16
+ */
17
+ export const ReadWriteVolumeHttp = Layer.effect(
18
+ ReadWriteVolume,
19
+ makeModalBinding({
20
+ tag: "Modal.ReadWriteVolume",
21
+ operations: VolumeFileOps,
22
+ role: "contributor",
23
+ make: Effect.fn(function* (volume: Volume, ops) {
24
+ const volumeId = yield* volume.volumeId;
25
+ return makeReadWriteVolumeClient(volumeId, ops);
26
+ }),
27
+ }),
28
+ );
@@ -0,0 +1,111 @@
1
+ import * as Binding from "alchemy/Binding";
2
+ import * as Output from "alchemy/Output";
3
+ import { CurrentRuntimeContext } from "alchemy/RuntimeContext";
4
+ import { Stack } from "alchemy/Stack";
5
+ import { Stage } from "alchemy/Stage";
6
+ import * as Effect from "effect/Effect";
7
+ import * as Option from "effect/Option";
8
+
9
+ /**
10
+ * Who created an object at run time: the stack, stage and binding host
11
+ * (`alchemy::stack`, `alchemy::stage`, `alchemy::id`).
12
+ *
13
+ * The `Create*` bindings mark every object they create with it, so the
14
+ * objects can be found and cleaned up. Destroying the stack does not delete
15
+ * them. Modal tags sandboxes, so a sandbox carries the three keys as tags;
16
+ * volumes, dicts, queues and secrets have only a name, so theirs starts with
17
+ * {@link runtimePrefix}, and `alchemy nuke` deletes them by it.
18
+ */
19
+ export interface RuntimeOwner {
20
+ readonly stack: string;
21
+ readonly stage: string;
22
+ readonly id: string;
23
+ }
24
+
25
+ /** The owner as Modal sandbox tags. */
26
+ export const runtimeTags = (owner: RuntimeOwner): Record<string, string> => ({
27
+ "alchemy::stack": owner.stack,
28
+ "alchemy::stage": owner.stage,
29
+ "alchemy::id": owner.id,
30
+ });
31
+
32
+ const toLabel = (value: string) =>
33
+ value
34
+ .toLowerCase()
35
+ .replace(/[^a-z0-9-]+/g, "-")
36
+ .replace(/-+/g, "-")
37
+ .replace(/^-|-$/g, "");
38
+
39
+ /** FNV-1a, 32 bits: a short, stable digest of the full identity. */
40
+ const digest = (value: string) => {
41
+ let hash = 0x811c9dc5;
42
+ for (let i = 0; i < value.length; i++) {
43
+ hash ^= value.charCodeAt(i);
44
+ hash = Math.imul(hash, 0x01000193);
45
+ }
46
+ return (hash >>> 0).toString(16).padStart(8, "0");
47
+ };
48
+
49
+ /**
50
+ * The name prefix of objects that carry only a name:
51
+ * `alc-<stack-stage-id>-<digest>`, the identity readable and cut to 16
52
+ * characters, then a digest of all three. An object `name` becomes
53
+ * `<prefix>-<name>`. The `alc-` marker is how `alchemy nuke` recognizes them.
54
+ */
55
+ export const runtimePrefix = (owner: RuntimeOwner): string => {
56
+ const readable =
57
+ toLabel(`${owner.stack}-${owner.stage}-${owner.id}`).slice(0, 16).replace(/-+$/, "") || "x";
58
+ return `alc-${readable}-${digest(`${owner.stack}/${owner.stage}/${owner.id}`)}`;
59
+ };
60
+
61
+ /** Whether `name` carries some owner's {@link runtimePrefix}. */
62
+ export const isRuntimeName = (name: string | undefined): boolean =>
63
+ name !== undefined && /^alc-[a-z0-9](?:[a-z0-9-]*[a-z0-9])?-[0-9a-f]{8}-./.test(name);
64
+
65
+ /** The name an object gets: `<prefix>-<name>` with an owner, `name` without one. */
66
+ export const ownedName = (owner: RuntimeOwner | undefined, name: string) =>
67
+ owner === undefined ? name : `${runtimePrefix(owner)}-${name}`;
68
+
69
+ /** An owned object's name without the prefix, or `undefined` when another owner's. */
70
+ export const unownedName = (owner: RuntimeOwner | undefined, name: string) => {
71
+ if (owner === undefined) return name;
72
+ const prefix = `${runtimePrefix(owner)}-`;
73
+ return name.startsWith(prefix) ? name.slice(prefix.length) : undefined;
74
+ };
75
+
76
+ const ENV = {
77
+ stack: "ALCHEMY_MODAL_OWNER_STACK",
78
+ stage: "ALCHEMY_MODAL_OWNER_STAGE",
79
+ id: "ALCHEMY_MODAL_OWNER_ID",
80
+ } as const;
81
+
82
+ /**
83
+ * The owner a `Create*` binding marks its objects with. Yield it while the
84
+ * binding's layer is built and call the result inside the binding: at deploy
85
+ * it binds the host's identity into the host's env; at run time its Effect
86
+ * reads it back. Without a host (a script or an Action) there is no owner.
87
+ */
88
+ export const RuntimeOwnerOf = Effect.fn(function* () {
89
+ const runtime = yield* CurrentRuntimeContext;
90
+ if (runtime === undefined) return Effect.succeed<RuntimeOwner | undefined>(undefined);
91
+ if (!globalThis.__ALCHEMY_RUNTIME__) {
92
+ const host = yield* Binding.Host;
93
+ // The deploying stack and stage, read without requiring them, so the
94
+ // binding's `make` needs nothing a script or an Action lacks.
95
+ const stack = Option.getOrUndefined(yield* Effect.serviceOption(Stack));
96
+ const stage = Option.getOrUndefined(yield* Effect.serviceOption(Stage));
97
+ if (host !== undefined && stack !== undefined && stage !== undefined) {
98
+ yield* runtime.set(ENV.stack, Output.literal(stack.name));
99
+ yield* runtime.set(ENV.stage, Output.literal(stage));
100
+ yield* runtime.set(ENV.id, Output.literal(host.LogicalId));
101
+ }
102
+ }
103
+ return Effect.gen(function* () {
104
+ const stack = yield* runtime.get<string>(ENV.stack);
105
+ const stage = yield* runtime.get<string>(ENV.stage);
106
+ const id = yield* runtime.get<string>(ENV.id);
107
+ return stack === undefined || stage === undefined || id === undefined
108
+ ? undefined
109
+ : ({ stack, stage, id } satisfies RuntimeOwner);
110
+ });
111
+ });
package/src/Sandbox.ts ADDED
@@ -0,0 +1,402 @@
1
+ import * as BuildPlan from "@alchemy.run/docker/BuildPlan";
2
+ import * as image from "@distilled.cloud/modal/image";
3
+ import * as secret from "@distilled.cloud/modal/secret";
4
+ import type * as Bundle from "alchemy/Bundle/Bundle";
5
+ import { deepEqual, isResolved } from "alchemy/Diff";
6
+ import { mountInstallLines } from "alchemy/Mount";
7
+ import { Platform, type Main, type PlatformProps } from "alchemy/Platform";
8
+ import * as Provider from "alchemy/Provider";
9
+ import type { Resource } from "alchemy/Resource";
10
+ import {
11
+ createHostRuntimeContext,
12
+ type HostRuntimeContext,
13
+ type ServerHost,
14
+ } from "alchemy/Runtime/Process";
15
+ import { Stack } from "alchemy/Stack";
16
+ import { sha256Object } from "alchemy/Util/sha256";
17
+ import * as Effect from "effect/Effect";
18
+ import * as Redacted from "effect/Redacted";
19
+ import type { App } from "./App.ts";
20
+ import { buildImage, ImageBuildOps } from "./ImageBuild.ts";
21
+ import { checkCommands, lowerPlan, MODAL_CAPABILITIES } from "./ImagePlan.ts";
22
+ import { envNameOf, objectName } from "./internal.ts";
23
+ import { resolveDeclarations } from "./internal/Declared.ts";
24
+ import {
25
+ boundCapabilities,
26
+ boundMounts,
27
+ checkModalMounts,
28
+ type ModalMounts,
29
+ type Mount,
30
+ type MountBindings,
31
+ type MountContract,
32
+ modalMountsOf,
33
+ } from "./Mounts.ts";
34
+ import type { Providers } from "./Providers.ts";
35
+ import { putSecret } from "./Secret.ts";
36
+
37
+ const DEFAULT_PORT = 8080;
38
+
39
+ type Ref<T> = T | Effect.Effect<T, never, Providers>;
40
+
41
+ export interface SandboxProps extends PlatformProps {
42
+ /**
43
+ * Module entrypoint, bundled and baked into the sandbox image. Typically
44
+ * `import.meta.url`. A change to the bundle builds a new image.
45
+ */
46
+ main: string;
47
+ /** The App sandboxes run in. */
48
+ app: Ref<App>;
49
+ /**
50
+ * Base image the bundle runs on. It needs Bun on the `PATH`.
51
+ * @default "oven/bun:1"
52
+ */
53
+ image?: string;
54
+ /** Dockerfile lines run on the base before the bundle is added. */
55
+ commands?: string[];
56
+ /**
57
+ * Port the program's `fetch` handler listens on, opened as an encrypted
58
+ * tunnel on every sandbox.
59
+ * @default 8080
60
+ */
61
+ port?: number;
62
+ /**
63
+ * Named export to load from `main`.
64
+ * @default "default"
65
+ */
66
+ handler?: string;
67
+ /**
68
+ * Extra environment variables for the program. Stored, with the
69
+ * bindings' env, in a Modal Secret attached to every sandbox.
70
+ */
71
+ env?: Record<string, any>;
72
+ /** Bundler options. */
73
+ build?: Bundle.BundleConfig;
74
+ /**
75
+ * Volumes and cloud buckets mounted into every sandbox:
76
+ * `[{ volume: Data, path: "/data" }]`. `Modal.MountVolume` and
77
+ * `Modal.MountBucket` in the program add more.
78
+ */
79
+ mounts?: Mount[];
80
+ }
81
+
82
+ export interface SandboxAttributes {
83
+ /** The image with the bundled program (`im-…`). */
84
+ imageId: string;
85
+ /** The App sandboxes run in. */
86
+ appId: string;
87
+ /** Name of the App. */
88
+ appName: string | undefined;
89
+ /** Environment of the App. */
90
+ environment: string | undefined;
91
+ /** The Modal Secret holding the program's env (bindings' credentials included). */
92
+ secretId: string;
93
+ /** Name of that secret. */
94
+ secretName: string;
95
+ /** Port the program listens on. */
96
+ port: number;
97
+ /** The command each sandbox runs. */
98
+ command: string[];
99
+ /** Modal's volume and bucket mounts every sandbox gets (props and bindings). */
100
+ mounts: ModalMounts;
101
+ /** Content hash of the bundle and image inputs. */
102
+ hash: string;
103
+ }
104
+
105
+ export type Sandbox = Resource<
106
+ "Modal.Sandbox",
107
+ SandboxProps,
108
+ SandboxAttributes,
109
+ { env?: Record<string, any>; mounts?: MountContract },
110
+ Providers
111
+ >;
112
+
113
+ export type SandboxServices = ServerHost;
114
+ export type SandboxShape = Main<SandboxServices>;
115
+ export type SandboxRuntimeContext = HostRuntimeContext;
116
+
117
+ /**
118
+ * An Effect program that runs in Modal sandboxes. Alchemy bundles `main`,
119
+ * builds it into an image on Modal's builder (no Docker), and stores its
120
+ * env, including the credentials its bindings need, in a Modal Secret.
121
+ * `Modal.CreateSandbox(Agent)` then boots sandboxes that run the program and
122
+ * serve its `fetch` handler; `sandbox.getTcpPort()` reaches it.
123
+ *
124
+ * Each sandbox is an isolated instance: give one to every user, session or
125
+ * task, and terminate it when the work is done. A sandbox lives at most 24
126
+ * hours. Bindings work inside it like on any host, so the program can read a
127
+ * Modal Volume or a Cloudflare R2 bucket.
128
+ *
129
+ * ### Effect program
130
+ * **Example:** An agent that answers over HTTP
131
+ * ```typescript
132
+ * // src/Agent.ts
133
+ * import * as Modal from "@alchemy.run/modal";
134
+ * import * as Effect from "effect/Effect";
135
+ * import * as HttpServerResponse from "effect/http/HttpServerResponse";
136
+ * import { Coder } from "./Coder.ts";
137
+ *
138
+ * export default class Agent extends Modal.Sandbox<Agent>()(
139
+ * "Agent",
140
+ * { main: import.meta.url, app: Coder },
141
+ * Effect.gen(function* () {
142
+ * return {
143
+ * fetch: Effect.succeed(HttpServerResponse.text("ready")),
144
+ * };
145
+ * }),
146
+ * ) {}
147
+ * ```
148
+ *
149
+ * ### Async program
150
+ * **Example:** A plain HTTP server, no Effect (it runs on Bun)
151
+ * ```typescript
152
+ * // src/Agent.ts
153
+ * import * as Modal from "@alchemy.run/modal";
154
+ * import { Coder } from "./Coder.ts";
155
+ *
156
+ * export const Agent = Modal.Sandbox("Agent", {
157
+ * main: "./src/agent-server.ts",
158
+ * app: Coder,
159
+ * env: { GREETING: "hello" },
160
+ * });
161
+ * export type AgentEnv = Modal.InferEnv<typeof Agent>;
162
+ * ```
163
+ *
164
+ * ```typescript
165
+ * // src/agent-server.ts
166
+ * import { createServer } from "node:http";
167
+ * import type { AgentEnv } from "./Agent.ts";
168
+ *
169
+ * const env = process.env as unknown as AgentEnv;
170
+ *
171
+ * createServer((_request, response) => response.end(env.GREETING)).listen(Number(process.env.PORT));
172
+ * ```
173
+ *
174
+ * ### Starting instances
175
+ * **Example:** One sandbox per request from a Worker
176
+ * ```typescript
177
+ * // src/Api.ts
178
+ * import * as Cloudflare from "@alchemy.run/cloudflare";
179
+ * import * as Modal from "@alchemy.run/modal";
180
+ * import * as Effect from "effect/Effect";
181
+ * import * as HttpClientRequest from "effect/http/HttpClientRequest";
182
+ * import * as HttpServerResponse from "effect/http/HttpServerResponse";
183
+ * import Agent from "./Agent.ts";
184
+ *
185
+ * export default class Api extends Cloudflare.Worker<Api>()(
186
+ * "Api",
187
+ * { main: import.meta.url, compatibility: { flags: ["nodejs_compat"] } },
188
+ * Effect.gen(function* () {
189
+ * const agents = yield* Modal.CreateSandbox(Agent);
190
+ * return {
191
+ * fetch: Effect.gen(function* () {
192
+ * const agent = yield* agents.create({ timeout: "10 minutes" });
193
+ * const port = yield* agent.getTcpPort();
194
+ * const response = yield* port.fetch(HttpClientRequest.get("/"));
195
+ * const text = yield* response.text;
196
+ * yield* agent.terminate();
197
+ * return HttpServerResponse.text(text);
198
+ * }).pipe(Effect.orDie),
199
+ * };
200
+ * }).pipe(Effect.provide(Modal.CreateSandboxHttp)),
201
+ * ) {}
202
+ * ```
203
+ *
204
+ * ### Bindings inside the sandbox
205
+ * **Example:** Read a Modal Volume from the program
206
+ * ```typescript
207
+ * // src/Agent.ts
208
+ * import * as Modal from "@alchemy.run/modal";
209
+ * import * as Effect from "effect/Effect";
210
+ * import * as HttpServerResponse from "effect/http/HttpServerResponse";
211
+ * import { Coder, Models } from "./Coder.ts";
212
+ *
213
+ * export default class Agent extends Modal.Sandbox<Agent>()(
214
+ * "Agent",
215
+ * { main: import.meta.url, app: Coder },
216
+ * Effect.gen(function* () {
217
+ * const models = yield* Modal.ReadVolume(Models);
218
+ * return {
219
+ * fetch: Effect.gen(function* () {
220
+ * const files = yield* models.listFiles("/");
221
+ * return yield* HttpServerResponse.json(files);
222
+ * }).pipe(Effect.orDie),
223
+ * };
224
+ * }).pipe(Effect.provide(Modal.ReadVolumeHttp)),
225
+ * ) {}
226
+ * ```
227
+ *
228
+ * ### Configuration
229
+ * **Example:** A GPU-ready base and a custom port
230
+ * ```typescript
231
+ * export default class Trainer extends Modal.Sandbox<Trainer>()(
232
+ * "Trainer",
233
+ * {
234
+ * main: import.meta.url,
235
+ * app: Coder,
236
+ * image: "nvidia/cuda:12.4.1-runtime-ubuntu22.04",
237
+ * commands: ["RUN apt-get update && apt-get install -y curl unzip && curl -fsSL https://bun.sh/install | bash && ln -s /root/.bun/bin/bun /usr/local/bin/bun"],
238
+ * port: 3000,
239
+ * },
240
+ * program,
241
+ * ) {}
242
+ * ```
243
+ *
244
+ * @resource
245
+ * @product Sandbox
246
+ */
247
+ export const Sandbox: Platform<Sandbox, SandboxServices, SandboxShape, SandboxRuntimeContext> =
248
+ Platform("Modal.Sandbox", {
249
+ createRuntimeContext: createHostRuntimeContext("Modal.Sandbox"),
250
+ // `{ app: Coder }` at module scope is an Effect: yield it so the App is
251
+ // registered and `news.app` is resolved attributes at reconcile.
252
+ transformProps: (_id, props) =>
253
+ Effect.gen(function* () {
254
+ if (globalThis.__ALCHEMY_RUNTIME__) return props;
255
+ const app = Effect.isEffect(props.app)
256
+ ? yield* props.app as Effect.Effect<App, never, Providers>
257
+ : props.app;
258
+ const mounts =
259
+ props.mounts === undefined
260
+ ? undefined
261
+ : ((yield* resolveDeclarations(props.mounts)) as Mount[]);
262
+ return { ...props, app, mounts };
263
+ }),
264
+ });
265
+
266
+ const bootstrapEntry =
267
+ (handler: string) =>
268
+ (importPath: string): string =>
269
+ `
270
+ import { bootstrap } from "@alchemy.run/modal/Bootstrap";
271
+ import { ${handler} as entrypoint } from ${JSON.stringify(importPath)};
272
+
273
+ await bootstrap(entrypoint);
274
+ `;
275
+
276
+ const appOf = (value: unknown) => {
277
+ const rec = (value ?? {}) as { appId?: string; name?: string; environment?: unknown };
278
+ return { appId: rec.appId ?? "", appName: rec.name, environment: envNameOf(rec.environment) };
279
+ };
280
+
281
+ /** An env value as a string, as the program's `process.env` sees it. */
282
+ const envText = (value: unknown): string =>
283
+ typeof value === "string"
284
+ ? value
285
+ : Redacted.isRedacted(value)
286
+ ? String(Redacted.value(value))
287
+ : JSON.stringify(value ?? null);
288
+
289
+ export const SandboxProvider = () =>
290
+ Provider.effect(
291
+ Sandbox,
292
+ Effect.gen(function* () {
293
+ const stack = yield* Stack;
294
+
295
+ /** Plan the program's image (bundle + bootstrap) with the shared BuildPlan. */
296
+ const prepare = Effect.fn(function* (
297
+ news: SandboxProps,
298
+ port: number,
299
+ bindings: MountBindings,
300
+ ) {
301
+ // Other providers' mount clients go into the image; Modal can't
302
+ // provide FUSE or NFS, so those that need it fail here.
303
+ const capabilities = boundCapabilities(bindings);
304
+ yield* checkModalMounts("Modal.Sandbox", capabilities);
305
+ const plan = yield* BuildPlan.plan(
306
+ {
307
+ main: news.main,
308
+ image: news.image,
309
+ handler: news.handler,
310
+ build: news.build,
311
+ },
312
+ {
313
+ capabilities: { ...MODAL_CAPABILITIES, target: "Modal.Sandbox" },
314
+ port,
315
+ bootstrap: news.isExternal ? undefined : bootstrapEntry(news.handler ?? "default"),
316
+ install: mountInstallLines(capabilities),
317
+ },
318
+ );
319
+ const extra = yield* checkCommands(news.commands ?? []);
320
+ const spec = yield* lowerPlan(plan, extra);
321
+ const hash = yield* sha256Object({ plan: plan.hash, extra });
322
+ const command = BuildPlan.startCommand(plan) ?? [];
323
+ return { spec, hash, command: [...command] };
324
+ });
325
+
326
+ return {
327
+ stables: ["appId", "secretName"],
328
+ diff: Effect.fn(function* ({ news, output, newBindings }) {
329
+ if (!isResolved(news) || !isResolved(newBindings) || output === undefined) {
330
+ return undefined;
331
+ }
332
+ if (appOf(news.app).appId !== output.appId) return { action: "replace" } as const;
333
+ const { hash } = yield* prepare(news, news.port ?? DEFAULT_PORT, newBindings);
334
+ if (hash !== output.hash) return { action: "update" } as const;
335
+ const mounts = yield* modalMountsOf([
336
+ ...(news.mounts ?? []),
337
+ ...boundMounts(newBindings),
338
+ ]);
339
+ return deepEqual(mounts, output.mounts) ? undefined : ({ action: "update" } as const);
340
+ }),
341
+ read: Effect.fn(function* ({ output }) {
342
+ if (output === undefined) return undefined;
343
+ const found = yield* image
344
+ .imageFromId({ imageId: output.imageId })
345
+ .pipe(Effect.catchTag("ImageNotFound", () => Effect.undefined));
346
+ return found?.imageId ? output : undefined;
347
+ }),
348
+ reconcile: Effect.fn(function* ({ id, news, output, session, bindings }) {
349
+ const app = appOf(news.app);
350
+ // The props' mounts, then the ones `Modal.MountVolume` / `MountBucket` bound.
351
+ const mounts = yield* modalMountsOf([...(news.mounts ?? []), ...boundMounts(bindings)]);
352
+ const port = news.port ?? DEFAULT_PORT;
353
+ const secretName = output?.secretName ?? `${yield* objectName(id, undefined, 58)}-env`;
354
+
355
+ // Sync the program's env (bindings' credentials included) into a
356
+ // secret every sandbox attaches; values never enter the image.
357
+ const env: Record<string, string> = {
358
+ ALCHEMY_STACK_NAME: stack.name,
359
+ ALCHEMY_STAGE: stack.stage,
360
+ ALCHEMY_PHASE: "runtime",
361
+ HOST: "0.0.0.0",
362
+ PORT: String(port),
363
+ };
364
+ for (const [key, value] of Object.entries(news.env ?? {})) env[key] = envText(value);
365
+ const stored = yield* putSecret(
366
+ yield* secret.secretGetOrCreate,
367
+ secretName,
368
+ app.environment,
369
+ env,
370
+ );
371
+
372
+ // Ensure the image: Modal reuses a cached build for the same inputs.
373
+ const { spec, hash, command } = yield* prepare(news, port, bindings);
374
+ const imageId =
375
+ output !== undefined && output.hash === hash && output.appId === app.appId
376
+ ? output.imageId
377
+ : yield* buildImage(yield* ImageBuildOps, app.appId, spec, { note: session.note });
378
+
379
+ return {
380
+ imageId,
381
+ appId: app.appId,
382
+ appName: app.appName,
383
+ environment: app.environment,
384
+ secretId: stored.secretId,
385
+ secretName,
386
+ port,
387
+ command,
388
+ mounts,
389
+ hash,
390
+ };
391
+ }),
392
+ delete: Effect.fn(function* ({ output }) {
393
+ yield* secret
394
+ .deleteSecret({ secretId: output.secretId })
395
+ .pipe(Effect.catchTag("SecretNotFound", () => Effect.void));
396
+ yield* image
397
+ .deleteImage({ imageId: output.imageId })
398
+ .pipe(Effect.catchTag("ImageNotFound", () => Effect.void));
399
+ }),
400
+ };
401
+ }),
402
+ );