@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,108 @@
1
+ import type {
2
+ VolumeGetFile2Error,
3
+ VolumeListFiles2Error,
4
+ VolumeRemoveFile2Error,
5
+ VolumeCopyFiles2Error,
6
+ VolumePutFiles2Error,
7
+ } from "@distilled.cloud/modal/volume";
8
+ import type { RuntimeContext } from "alchemy/RuntimeContext";
9
+ import * as Effect from "effect/Effect";
10
+ import type { HttpClientError } from "effect/http/HttpClientError";
11
+ import {
12
+ copyVolumeFiles,
13
+ listVolumeFiles,
14
+ readVolumeFile,
15
+ removeVolumeFile,
16
+ writeVolumeFile,
17
+ type VolumeFileEntry,
18
+ type VolumeFileOps,
19
+ type VolumeTransferError,
20
+ } from "./VolumeFiles.ts";
21
+
22
+ /** Errors reading a volume file: `VolumeFileNotFound` when the path is missing. */
23
+ export type ReadVolumeFileError = VolumeGetFile2Error | VolumeTransferError | HttpClientError;
24
+ /** Errors listing a volume directory. */
25
+ export type ListVolumeFilesError = VolumeListFiles2Error;
26
+ /** Errors removing or copying volume files. */
27
+ export type ChangeVolumeFilesError = VolumeRemoveFile2Error | VolumeCopyFiles2Error;
28
+ /** Errors writing a volume file. */
29
+ export type WriteVolumeFileError = VolumePutFiles2Error | VolumeTransferError | HttpClientError;
30
+
31
+ /** Read access to one volume's files. */
32
+ export interface ReadVolumeClient {
33
+ /** The volume's id. */
34
+ readonly volumeId: Effect.Effect<string>;
35
+ /** Read a file. */
36
+ readFile(path: string): Effect.Effect<Uint8Array, ReadVolumeFileError, RuntimeContext>;
37
+ /** Read a UTF-8 file. */
38
+ readFileString(path: string): Effect.Effect<string, ReadVolumeFileError, RuntimeContext>;
39
+ /** List a directory (`recursive` walks it). */
40
+ listFiles(
41
+ path: string,
42
+ options?: { readonly recursive?: boolean },
43
+ ): Effect.Effect<ReadonlyArray<VolumeFileEntry>, ListVolumeFilesError, RuntimeContext>;
44
+ }
45
+
46
+ /** Write access to one volume's files. */
47
+ export interface WriteVolumeClient {
48
+ /** The volume's id. */
49
+ readonly volumeId: Effect.Effect<string>;
50
+ /** Write (create or replace) a file. */
51
+ writeFile(
52
+ path: string,
53
+ data: string | Uint8Array,
54
+ options?: { readonly mode?: number },
55
+ ): Effect.Effect<void, WriteVolumeFileError, RuntimeContext>;
56
+ /** Remove a file, or a directory with `recursive`. */
57
+ removeFile(
58
+ path: string,
59
+ options?: { readonly recursive?: boolean },
60
+ ): Effect.Effect<void, ChangeVolumeFilesError, RuntimeContext>;
61
+ /** Copy files to `destination` inside the volume. */
62
+ copyFiles(
63
+ sources: ReadonlyArray<string>,
64
+ destination: string,
65
+ options?: { readonly recursive?: boolean },
66
+ ): Effect.Effect<void, ChangeVolumeFilesError, RuntimeContext>;
67
+ }
68
+
69
+ /** Read and write access to one volume's files. */
70
+ export interface ReadWriteVolumeClient extends ReadVolumeClient, WriteVolumeClient {}
71
+
72
+ /** The read half of a volume client over `volumeId`. */
73
+ export const makeReadVolumeClient = (
74
+ volumeId: Effect.Effect<string>,
75
+ ops: VolumeFileOps,
76
+ ): ReadVolumeClient => ({
77
+ volumeId,
78
+ readFile: (path) => Effect.flatMap(volumeId, (id) => readVolumeFile(ops, id, path)),
79
+ readFileString: (path) =>
80
+ Effect.flatMap(volumeId, (id) => readVolumeFile(ops, id, path)).pipe(
81
+ Effect.map((bytes) => new TextDecoder().decode(bytes)),
82
+ ),
83
+ listFiles: (path, options) =>
84
+ Effect.flatMap(volumeId, (id) => listVolumeFiles(ops, id, path, options)),
85
+ });
86
+
87
+ /** The write half of a volume client over `volumeId`. */
88
+ export const makeWriteVolumeClient = (
89
+ volumeId: Effect.Effect<string>,
90
+ ops: VolumeFileOps,
91
+ ): WriteVolumeClient => ({
92
+ volumeId,
93
+ writeFile: (path, data, options) =>
94
+ Effect.flatMap(volumeId, (id) => writeVolumeFile(ops, id, path, data, options)),
95
+ removeFile: (path, options) =>
96
+ Effect.flatMap(volumeId, (id) => removeVolumeFile(ops, id, path, options)),
97
+ copyFiles: (sources, destination, options) =>
98
+ Effect.flatMap(volumeId, (id) => copyVolumeFiles(ops, id, sources, destination, options)),
99
+ });
100
+
101
+ /** A read-write volume client over `volumeId`. */
102
+ export const makeReadWriteVolumeClient = (
103
+ volumeId: Effect.Effect<string>,
104
+ ops: VolumeFileOps,
105
+ ): ReadWriteVolumeClient => ({
106
+ ...makeReadVolumeClient(volumeId, ops),
107
+ ...makeWriteVolumeClient(volumeId, ops),
108
+ });
@@ -0,0 +1,194 @@
1
+ import { createHash } from "node:crypto";
2
+ import * as volume from "@distilled.cloud/modal/volume";
3
+ import * as Data from "effect/Data";
4
+ import * as Effect from "effect/Effect";
5
+ import * as HttpClient from "effect/http/HttpClient";
6
+ import * as HttpClientRequest from "effect/http/HttpClientRequest";
7
+ import { operations } from "./internal.ts";
8
+
9
+ /** A block upload or download to a URL Modal handed out failed. */
10
+ export class VolumeTransferError extends Data.TaggedError("Modal.VolumeTransferError")<{
11
+ readonly path: string;
12
+ readonly message: string;
13
+ }> {}
14
+
15
+ /** One entry of a volume directory listing. */
16
+ export interface VolumeFileEntry {
17
+ /** Path relative to the volume root. */
18
+ readonly path: string;
19
+ readonly type: "file" | "directory" | "symlink" | "other";
20
+ /** Size in bytes (files). */
21
+ readonly size: number;
22
+ /** Modification time, seconds since the epoch. */
23
+ readonly mtime: number;
24
+ }
25
+
26
+ const BLOCK_SIZE = 8 * 1024 * 1024;
27
+
28
+ /** The operations a volume's files need, resolved by `ModalBindings.withCredentials`. */
29
+ export const VolumeFileOps = operations({
30
+ getFile: volume.volumeGetFile2,
31
+ listFiles: volume.volumeListFiles2,
32
+ putFiles: volume.volumePutFiles2,
33
+ removeFile: volume.volumeRemoveFile2,
34
+ copyFiles: volume.volumeCopyFiles2,
35
+ http: HttpClient.HttpClient,
36
+ });
37
+
38
+ export type VolumeFileOps = Effect.Success<typeof VolumeFileOps>;
39
+
40
+ const typeOf = (type: string | undefined): VolumeFileEntry["type"] =>
41
+ type === "FILE"
42
+ ? "file"
43
+ : type === "DIRECTORY"
44
+ ? "directory"
45
+ : type === "SYMLINK"
46
+ ? "symlink"
47
+ : "other";
48
+
49
+ const toBytes = (data: string | Uint8Array) =>
50
+ Effect.sync(() => (typeof data === "string" ? new TextEncoder().encode(data) : data));
51
+
52
+ /**
53
+ * Read a file from a (v2) volume: Modal returns presigned URLs for the
54
+ * file's blocks, which are fetched and concatenated.
55
+ */
56
+ export const readVolumeFile = Effect.fn(function* (
57
+ ops: VolumeFileOps,
58
+ volumeId: string,
59
+ path: string,
60
+ ) {
61
+ const { getUrls, size } = yield* ops.getFile({ volumeId, path });
62
+ const total = Number(size ?? 0);
63
+ const out = new Uint8Array(total);
64
+ let offset = 0;
65
+ for (const url of getUrls ?? []) {
66
+ // A presigned block URL returned by VolumeGetFile2 (allowed raw HTTP).
67
+ const response = yield* ops.http.execute(HttpClientRequest.get(url));
68
+ if (response.status >= 300) {
69
+ return yield* new VolumeTransferError({
70
+ path,
71
+ message: `Downloading a block of ${path} failed with HTTP ${response.status}`,
72
+ });
73
+ }
74
+ const buffer = yield* response.arrayBuffer;
75
+ const block = new Uint8Array(buffer);
76
+ out.set(block.subarray(0, Math.max(0, total - offset)), offset);
77
+ offset += Math.min(block.length, BLOCK_SIZE);
78
+ }
79
+ return out;
80
+ });
81
+
82
+ /** List a directory of a (v2) volume. */
83
+ export const listVolumeFiles = Effect.fn(function* (
84
+ ops: VolumeFileOps,
85
+ volumeId: string,
86
+ path: string,
87
+ options: { readonly recursive?: boolean } = {},
88
+ ) {
89
+ const { items } = yield* ops.listFiles({
90
+ volumeId,
91
+ path,
92
+ recursive: options.recursive ?? false,
93
+ });
94
+ return items.flatMap((batch) =>
95
+ (batch.entries ?? []).map((entry): VolumeFileEntry => ({
96
+ path: entry.path ?? "",
97
+ type: typeOf(entry.type),
98
+ size: Number(entry.size ?? 0),
99
+ mtime: Number(entry.mtime ?? 0),
100
+ })),
101
+ );
102
+ });
103
+
104
+ /**
105
+ * Write a file to a (v2) volume: send each 8 MiB block's SHA-256, upload
106
+ * the blocks Modal reports missing to the URLs it returns, then commit with
107
+ * the upload responses.
108
+ */
109
+ export const writeVolumeFile = Effect.fn(function* (
110
+ ops: VolumeFileOps,
111
+ volumeId: string,
112
+ path: string,
113
+ data: string | Uint8Array,
114
+ options: { readonly mode?: number } = {},
115
+ ) {
116
+ const bytes = yield* toBytes(data);
117
+ const blocks = yield* Effect.sync(() => {
118
+ const out: { readonly data: Uint8Array; readonly sha256: string }[] = [];
119
+ for (let offset = 0; offset === 0 || offset < bytes.length; offset += BLOCK_SIZE) {
120
+ const block = bytes.subarray(offset, offset + BLOCK_SIZE);
121
+ out.push({ data: block, sha256: createHash("sha256").update(block).digest("base64") });
122
+ if (bytes.length === 0) break;
123
+ }
124
+ return out;
125
+ });
126
+ const putResponses = new Map<number, string>();
127
+ for (let round = 0; round < 3; round++) {
128
+ const { missingBlocks } = yield* ops.putFiles({
129
+ volumeId,
130
+ files: [
131
+ {
132
+ path,
133
+ size: String(bytes.length),
134
+ mode: options.mode ?? 0o644,
135
+ blocks: blocks.map((block, index) => ({
136
+ contentsSha256: block.sha256,
137
+ putResponse: putResponses.get(index),
138
+ })),
139
+ },
140
+ ],
141
+ });
142
+ if (!missingBlocks || missingBlocks.length === 0) return;
143
+ for (const missing of missingBlocks) {
144
+ const index = Number(missing.blockIndex ?? 0);
145
+ const block = blocks[index];
146
+ if (!block || !missing.putUrl) continue;
147
+ // A presigned block URL returned by VolumePutFiles2 (allowed raw HTTP).
148
+ const response = yield* ops.http.execute(
149
+ HttpClientRequest.put(missing.putUrl).pipe(
150
+ HttpClientRequest.bodyUint8Array(block.data, "application/octet-stream"),
151
+ ),
152
+ );
153
+ if (response.status >= 300) {
154
+ return yield* new VolumeTransferError({
155
+ path,
156
+ message: `Uploading block ${index} of ${path} failed with HTTP ${response.status}`,
157
+ });
158
+ }
159
+ const body = yield* response.arrayBuffer;
160
+ const encoded = yield* Effect.sync(() => Buffer.from(body).toString("base64"));
161
+ putResponses.set(index, encoded);
162
+ }
163
+ }
164
+ return yield* new VolumeTransferError({
165
+ path,
166
+ message: `Modal kept reporting blocks of ${path} missing after upload`,
167
+ });
168
+ });
169
+
170
+ /** Remove a file (or, with `recursive`, a directory) from a (v2) volume. */
171
+ export const removeVolumeFile = Effect.fn(function* (
172
+ ops: VolumeFileOps,
173
+ volumeId: string,
174
+ path: string,
175
+ options: { readonly recursive?: boolean } = {},
176
+ ) {
177
+ yield* ops.removeFile({ volumeId, path, recursive: options.recursive ?? false });
178
+ });
179
+
180
+ /** Copy files inside a (v2) volume. */
181
+ export const copyVolumeFiles = Effect.fn(function* (
182
+ ops: VolumeFileOps,
183
+ volumeId: string,
184
+ sources: ReadonlyArray<string>,
185
+ destination: string,
186
+ options: { readonly recursive?: boolean } = {},
187
+ ) {
188
+ yield* ops.copyFiles({
189
+ volumeId,
190
+ srcPaths: [...sources],
191
+ dstPath: destination,
192
+ recursive: options.recursive ?? false,
193
+ });
194
+ });
@@ -0,0 +1,230 @@
1
+ import * as environment from "@distilled.cloud/modal/environment";
2
+ import * as webhook from "@distilled.cloud/modal/webhook";
3
+ import { isResolved } from "alchemy/Diff";
4
+ import * as Provider from "alchemy/Provider";
5
+ import { Resource } from "alchemy/Resource";
6
+ import * as Data from "effect/Data";
7
+ import * as Effect from "effect/Effect";
8
+ import * as Redacted from "effect/Redacted";
9
+ import { objectName } from "./internal.ts";
10
+ import { declarable } from "./internal/Declared.ts";
11
+ import type { Providers } from "./Providers.ts";
12
+
13
+ export class WebhookTokenUnexpectedResponse extends Data.TaggedError(
14
+ "Modal.WebhookTokenUnexpectedResponse",
15
+ )<{
16
+ readonly message: string;
17
+ }> {}
18
+
19
+ export interface WebhookTokenProps {
20
+ /**
21
+ * Display name of the token. If omitted, one is generated from the stack,
22
+ * stage and logical ID. Changing it renames the token in place.
23
+ */
24
+ name?: string;
25
+ /**
26
+ * Limit the token to the environments in {@link environments}. Changing it
27
+ * replaces the token (and its secret).
28
+ * @default false
29
+ */
30
+ scoped?: boolean;
31
+ /**
32
+ * Environments a scoped token works in: environment IDs, or yielded
33
+ * `Modal.Environment`s. Ignored unless {@link scoped} is set.
34
+ */
35
+ environments?: Array<string | { readonly environmentId: string }>;
36
+ }
37
+
38
+ export interface WebhookTokenAttributes {
39
+ /** Token ID (`wk-…`), sent as the `Modal-Key` header. */
40
+ tokenId: string;
41
+ /** Token secret (`ws-…`), sent as the `Modal-Secret` header. */
42
+ tokenSecret: Redacted.Redacted<string>;
43
+ /** Display name. */
44
+ name: string;
45
+ /** Whether the token is limited to {@link WebhookTokenProps.environments}. */
46
+ scoped: boolean;
47
+ /** Environment IDs a scoped token works in. */
48
+ environments: string[];
49
+ }
50
+
51
+ /**
52
+ * A Modal proxy auth token: the `Modal-Key` / `Modal-Secret` header pair
53
+ * that web endpoints and sandbox tunnels created with proxy authentication
54
+ * require. A scoped token works only in the environments it lists.
55
+ *
56
+ * Modal shows a token's secret once, at creation, so a token deleted outside
57
+ * Alchemy is recreated with a new secret on the next deploy. Tokens have no
58
+ * unique names, so they can't be adopted and aren't listed for
59
+ * `alchemy nuke`.
60
+ *
61
+ * ### Creating a token
62
+ * **Example:** A workspace-wide token
63
+ * ```typescript
64
+ * import * as Modal from "@alchemy.run/modal";
65
+ *
66
+ * export const Caller = Modal.WebhookToken("Caller", {});
67
+ * ```
68
+ *
69
+ * **Example:** A token scoped to one environment
70
+ * ```typescript
71
+ * import * as Modal from "@alchemy.run/modal";
72
+ *
73
+ * export const Agents = Modal.Environment("Agents", {});
74
+ * export const AgentsCaller = Modal.WebhookToken("AgentsCaller", {
75
+ * scoped: true,
76
+ * environments: [Agents],
77
+ * });
78
+ * ```
79
+ *
80
+ * ### Calling a protected endpoint
81
+ * **Example:** Send the header pair
82
+ * ```typescript
83
+ * const token = yield* AgentsCaller;
84
+ * const response = yield* HttpClient.get(url, {
85
+ * headers: {
86
+ * "Modal-Key": token.tokenId,
87
+ * "Modal-Secret": Redacted.value(token.tokenSecret),
88
+ * },
89
+ * });
90
+ * ```
91
+ *
92
+ * @resource
93
+ * @product WebhookToken
94
+ */
95
+ export const WebhookToken = declarable<WebhookToken>()(
96
+ Resource<WebhookToken>("Modal.WebhookToken"),
97
+ );
98
+
99
+ export type WebhookToken = Resource<
100
+ "Modal.WebhookToken",
101
+ WebhookTokenProps,
102
+ WebhookTokenAttributes,
103
+ never,
104
+ Providers
105
+ >;
106
+
107
+ export const WebhookTokenProvider = () =>
108
+ Provider.effect(
109
+ WebhookToken,
110
+ Effect.gen(function* () {
111
+ const observe = Effect.fn(function* (tokenId: string) {
112
+ const { tokens } = yield* webhook.listWebhookToken({});
113
+ return (tokens ?? []).find((token) => token.tokenId === tokenId);
114
+ });
115
+
116
+ return {
117
+ stables: ["tokenId", "tokenSecret", "scoped"],
118
+ diff: Effect.fn(function* ({ news, olds }) {
119
+ if (!isResolved(news)) return undefined;
120
+ if ((news.scoped ?? false) !== (olds?.scoped ?? false)) {
121
+ return { action: "replace" } as const;
122
+ }
123
+ return undefined;
124
+ }),
125
+ read: Effect.fn(function* ({ output }) {
126
+ if (output === undefined) return undefined;
127
+ const found = yield* observe(output.tokenId);
128
+ if (!found) return undefined;
129
+ return { ...output, name: found.name ?? output.name, scoped: found.scoped ?? false };
130
+ }),
131
+ reconcile: Effect.fn(function* ({ id, news, output, session }) {
132
+ const name = yield* objectName(id, news.name);
133
+ const scoped = news.scoped ?? false;
134
+
135
+ // Observe: only a token we created (its secret is in state) can be kept.
136
+ const found = output !== undefined ? yield* observe(output.tokenId) : undefined;
137
+ let current: WebhookTokenAttributes;
138
+ if (found && output) {
139
+ current = { ...output, name: found.name ?? output.name };
140
+ } else {
141
+ // A token under our generated name that state doesn't hold is
142
+ // left from a create that failed before state was saved; its
143
+ // secret is lost, so replace it.
144
+ if (news.name === undefined) {
145
+ const { tokens } = yield* webhook.listWebhookToken({});
146
+ for (const stale of (tokens ?? []).filter((t) => t.name === name)) {
147
+ if (!stale.tokenId) continue;
148
+ yield* webhook
149
+ .deleteWebhookToken({ tokenId: stale.tokenId })
150
+ .pipe(Effect.catchTag("WebhookTokenNotFound", () => Effect.void));
151
+ }
152
+ }
153
+ // Ensure
154
+ yield* session.note(`Creating webhook token ${name}...`);
155
+ const created = yield* webhook.createWebhookToken({ name, scoped });
156
+ if (!created.tokenId || created.tokenSecret === undefined) {
157
+ return yield* new WebhookTokenUnexpectedResponse({
158
+ message: `Modal returned no token for ${name}`,
159
+ });
160
+ }
161
+ current = {
162
+ tokenId: created.tokenId,
163
+ tokenSecret: Redacted.isRedacted(created.tokenSecret)
164
+ ? created.tokenSecret
165
+ : Redacted.make(created.tokenSecret),
166
+ name,
167
+ scoped,
168
+ environments: [],
169
+ };
170
+ }
171
+
172
+ // Sync the name.
173
+ if (current.name !== name) {
174
+ yield* webhook.updateWebhookToken({ tokenId: current.tokenId, name });
175
+ current = { ...current, name };
176
+ }
177
+
178
+ // Sync environments against the observed set.
179
+ if (scoped) {
180
+ // Modal doesn't serve `WebhookTokenEnvironmentList`, so read the
181
+ // token's environments from each environment's token list.
182
+ const { items } = yield* environment.listEnvironment({});
183
+ const observed = new Set<string>();
184
+ for (const env of items ?? []) {
185
+ if (!env.environmentId || !env.name) continue;
186
+ // An environment deleted since the list holds no tokens.
187
+ const { tokens } = yield* webhook
188
+ .webhookTokenListForEnvironment({ environmentName: env.name })
189
+ .pipe(Effect.catchTag("EnvironmentNotFound", () => Effect.succeed({ tokens: [] })));
190
+ if ((tokens ?? []).some((token) => token.tokenId === current.tokenId)) {
191
+ observed.add(env.environmentId);
192
+ }
193
+ }
194
+ const desired = new Set(
195
+ (news.environments ?? []).flatMap((env) =>
196
+ typeof env === "string"
197
+ ? [env]
198
+ : typeof env === "object" && env !== null && "environmentId" in env
199
+ ? [env.environmentId]
200
+ : [],
201
+ ),
202
+ );
203
+ for (const environmentId of desired) {
204
+ if (!observed.has(environmentId)) {
205
+ yield* webhook.addWebhookTokenEnvironment({
206
+ tokenId: current.tokenId,
207
+ environmentId,
208
+ });
209
+ }
210
+ }
211
+ for (const environmentId of observed) {
212
+ if (!desired.has(environmentId)) {
213
+ yield* webhook.removeWebhookTokenEnvironment({
214
+ tokenId: current.tokenId,
215
+ environmentId,
216
+ });
217
+ }
218
+ }
219
+ current = { ...current, environments: [...desired] };
220
+ }
221
+ return current;
222
+ }),
223
+ delete: Effect.fn(function* ({ output }) {
224
+ yield* webhook
225
+ .deleteWebhookToken({ tokenId: output.tokenId })
226
+ .pipe(Effect.catchTag("WebhookTokenNotFound", () => Effect.void));
227
+ }),
228
+ };
229
+ }),
230
+ );
@@ -0,0 +1,160 @@
1
+ import * as workspace from "@distilled.cloud/modal/workspace";
2
+ import * as Provider from "alchemy/Provider";
3
+ import { Resource } from "alchemy/Resource";
4
+ import * as Effect from "effect/Effect";
5
+ import { envNameOf, type EnvironmentInput } from "./internal.ts";
6
+ import { declarable } from "./internal/Declared.ts";
7
+ import type { Providers } from "./Providers.ts";
8
+
9
+ export interface WorkspaceSettingsProps {
10
+ /**
11
+ * Environment that Modal clients use when none is named (the `modal` CLI,
12
+ * `environmentName: ""` on the API).
13
+ */
14
+ defaultEnvironment?: EnvironmentInput;
15
+ /**
16
+ * Image builder version for new image builds in the workspace (e.g.
17
+ * `"2025.06"`). Changing it rebuilds images on their next use.
18
+ */
19
+ imageBuilderVersion?: string;
20
+ /**
21
+ * Require authentication on web endpoints and tunnels in environments
22
+ * that inherit the workspace default.
23
+ */
24
+ blockUnauthenticatedResources?: boolean;
25
+ }
26
+
27
+ export interface WorkspaceSettingsAttributes {
28
+ /** The workspace's default environment. */
29
+ defaultEnvironment: string | undefined;
30
+ /** The workspace's image builder version. */
31
+ imageBuilderVersion: string | undefined;
32
+ /** Settings found before the first deploy, restored on destroy. */
33
+ original: {
34
+ defaultEnvironment: string | undefined;
35
+ imageBuilderVersion: string | undefined;
36
+ };
37
+ }
38
+
39
+ /**
40
+ * Workspace-wide Modal settings: the default environment, the image builder
41
+ * version, and whether endpoints in inheriting environments require
42
+ * authentication.
43
+ *
44
+ * A workspace has one set of settings, so declare this resource once. It
45
+ * captures the settings it finds on first deploy and restores them when
46
+ * destroyed.
47
+ *
48
+ * ### Configuring the workspace
49
+ * **Example:** Pin the image builder and default environment
50
+ * ```typescript
51
+ * import * as Modal from "@alchemy.run/modal";
52
+ *
53
+ * export const Agents = Modal.Environment("Agents", {});
54
+ * export const Settings = Modal.WorkspaceSettings("Settings", {
55
+ * defaultEnvironment: Agents,
56
+ * imageBuilderVersion: "2025.06",
57
+ * });
58
+ * ```
59
+ *
60
+ * @resource
61
+ * @product Workspace
62
+ */
63
+ export const WorkspaceSettings = declarable<WorkspaceSettings>()(
64
+ Resource<WorkspaceSettings>("Modal.WorkspaceSettings"),
65
+ );
66
+
67
+ export type WorkspaceSettings = Resource<
68
+ "Modal.WorkspaceSettings",
69
+ WorkspaceSettingsProps,
70
+ WorkspaceSettingsAttributes,
71
+ never,
72
+ Providers
73
+ >;
74
+
75
+ export const WorkspaceSettingsProvider = () =>
76
+ Provider.effect(
77
+ WorkspaceSettings,
78
+ Effect.gen(function* () {
79
+ const observe = workspace.workspaceSettings({});
80
+
81
+ return {
82
+ read: Effect.fn(function* ({ output }) {
83
+ if (output === undefined) return undefined;
84
+ const current = yield* observe;
85
+ return {
86
+ ...output,
87
+ defaultEnvironment: current.defaultEnvironmentName || undefined,
88
+ imageBuilderVersion: current.imageBuilderVersion || undefined,
89
+ };
90
+ }),
91
+ reconcile: Effect.fn(function* ({ news, output }) {
92
+ // Observe
93
+ const current = yield* observe;
94
+ const original = output?.original ?? {
95
+ defaultEnvironment: current.defaultEnvironmentName || undefined,
96
+ imageBuilderVersion: current.imageBuilderVersion || undefined,
97
+ };
98
+ // Sync each setting against the observed value.
99
+ const defaultEnvironment = envNameOf(news.defaultEnvironment);
100
+ if (
101
+ defaultEnvironment !== undefined &&
102
+ defaultEnvironment !== current.defaultEnvironmentName
103
+ ) {
104
+ yield* workspace.workspaceSetDefaultEnvironment({
105
+ environmentName: defaultEnvironment,
106
+ });
107
+ }
108
+ if (
109
+ news.imageBuilderVersion !== undefined &&
110
+ news.imageBuilderVersion !== current.imageBuilderVersion
111
+ ) {
112
+ yield* workspace.workspaceSetImageBuilderVersion({
113
+ newImageBuilderVersion: news.imageBuilderVersion,
114
+ });
115
+ }
116
+ if (news.blockUnauthenticatedResources !== undefined) {
117
+ yield* workspace.workspaceSetDefaultEnvironmentSettings({
118
+ blockUnauthenticatedResources: news.blockUnauthenticatedResources
119
+ ? "ENVIRONMENT_BLOCK_UNAUTHENTICATED_RESOURCES_BLOCK"
120
+ : "ENVIRONMENT_BLOCK_UNAUTHENTICATED_RESOURCES_ALLOW",
121
+ });
122
+ }
123
+ const final = yield* observe;
124
+ return {
125
+ defaultEnvironment: final.defaultEnvironmentName || undefined,
126
+ imageBuilderVersion: final.imageBuilderVersion || undefined,
127
+ original,
128
+ };
129
+ }),
130
+ delete: Effect.fn(function* ({ output, olds }) {
131
+ // Restore what was there before Alchemy managed the settings.
132
+ const current = yield* observe;
133
+ if (
134
+ olds.defaultEnvironment !== undefined &&
135
+ output.original.defaultEnvironment !== undefined &&
136
+ current.defaultEnvironmentName !== output.original.defaultEnvironment
137
+ ) {
138
+ yield* workspace.workspaceSetDefaultEnvironment({
139
+ environmentName: output.original.defaultEnvironment,
140
+ });
141
+ }
142
+ if (
143
+ olds.imageBuilderVersion !== undefined &&
144
+ output.original.imageBuilderVersion !== undefined &&
145
+ current.imageBuilderVersion !== output.original.imageBuilderVersion
146
+ ) {
147
+ yield* workspace.workspaceSetImageBuilderVersion({
148
+ newImageBuilderVersion: output.original.imageBuilderVersion,
149
+ });
150
+ }
151
+ if (olds.blockUnauthenticatedResources !== undefined) {
152
+ yield* workspace.workspaceSetDefaultEnvironmentSettings({
153
+ blockUnauthenticatedResources:
154
+ "ENVIRONMENT_BLOCK_UNAUTHENTICATED_RESOURCES_UNSPECIFIED",
155
+ });
156
+ }
157
+ }),
158
+ };
159
+ }),
160
+ );