@alchemy.run/fly 0.0.0 → 2.0.0-beta.84

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 +57 -4
  3. package/lib/App.d.ts +230 -0
  4. package/lib/App.d.ts.map +1 -0
  5. package/lib/App.js +340 -0
  6. package/lib/App.js.map +1 -0
  7. package/lib/AuthProvider.d.ts +22 -0
  8. package/lib/AuthProvider.d.ts.map +1 -0
  9. package/lib/AuthProvider.js +48 -0
  10. package/lib/AuthProvider.js.map +1 -0
  11. package/lib/BindService.d.ts +159 -0
  12. package/lib/BindService.d.ts.map +1 -0
  13. package/lib/BindService.js +222 -0
  14. package/lib/BindService.js.map +1 -0
  15. package/lib/Bootstrap.d.ts +8 -0
  16. package/lib/Bootstrap.d.ts.map +1 -0
  17. package/lib/Bootstrap.js +41 -0
  18. package/lib/Bootstrap.js.map +1 -0
  19. package/lib/Bucket.d.ts +278 -0
  20. package/lib/Bucket.d.ts.map +1 -0
  21. package/lib/Bucket.js +658 -0
  22. package/lib/Bucket.js.map +1 -0
  23. package/lib/BucketBinding.d.ts +33 -0
  24. package/lib/BucketBinding.d.ts.map +1 -0
  25. package/lib/BucketBinding.js +70 -0
  26. package/lib/BucketBinding.js.map +1 -0
  27. package/lib/Catalog.d.ts +28 -0
  28. package/lib/Catalog.d.ts.map +1 -0
  29. package/lib/Catalog.js +31 -0
  30. package/lib/Catalog.js.map +1 -0
  31. package/lib/Certificate.d.ts +189 -0
  32. package/lib/Certificate.d.ts.map +1 -0
  33. package/lib/Certificate.js +380 -0
  34. package/lib/Certificate.js.map +1 -0
  35. package/lib/Checkpoint.d.ts +55 -0
  36. package/lib/Checkpoint.d.ts.map +1 -0
  37. package/lib/Checkpoint.js +3 -0
  38. package/lib/Checkpoint.js.map +1 -0
  39. package/lib/CheckpointHttp.d.ts +22 -0
  40. package/lib/CheckpointHttp.d.ts.map +1 -0
  41. package/lib/CheckpointHttp.js +53 -0
  42. package/lib/CheckpointHttp.js.map +1 -0
  43. package/lib/ConnectPostgres.d.ts +58 -0
  44. package/lib/ConnectPostgres.d.ts.map +1 -0
  45. package/lib/ConnectPostgres.js +13 -0
  46. package/lib/ConnectPostgres.js.map +1 -0
  47. package/lib/ConnectPostgresHttp.d.ts +26 -0
  48. package/lib/ConnectPostgresHttp.d.ts.map +1 -0
  49. package/lib/ConnectPostgresHttp.js +57 -0
  50. package/lib/ConnectPostgresHttp.js.map +1 -0
  51. package/lib/Contributions.d.ts +7 -0
  52. package/lib/Contributions.d.ts.map +1 -0
  53. package/lib/Contributions.js +6 -0
  54. package/lib/Contributions.js.map +1 -0
  55. package/lib/Credentials.d.ts +33 -0
  56. package/lib/Credentials.d.ts.map +1 -0
  57. package/lib/Credentials.js +59 -0
  58. package/lib/Credentials.js.map +1 -0
  59. package/lib/Decrypt.d.ts +52 -0
  60. package/lib/Decrypt.d.ts.map +1 -0
  61. package/lib/Decrypt.js +3 -0
  62. package/lib/Decrypt.js.map +1 -0
  63. package/lib/DecryptHttp.d.ts +22 -0
  64. package/lib/DecryptHttp.d.ts.map +1 -0
  65. package/lib/DecryptHttp.js +43 -0
  66. package/lib/DecryptHttp.js.map +1 -0
  67. package/lib/DeleteObject.d.ts +29 -0
  68. package/lib/DeleteObject.d.ts.map +1 -0
  69. package/lib/DeleteObject.js +3 -0
  70. package/lib/DeleteObject.js.map +1 -0
  71. package/lib/DeleteObjectHttp.d.ts +12 -0
  72. package/lib/DeleteObjectHttp.d.ts.map +1 -0
  73. package/lib/DeleteObjectHttp.js +17 -0
  74. package/lib/DeleteObjectHttp.js.map +1 -0
  75. package/lib/Deployment.d.ts +51 -0
  76. package/lib/Deployment.d.ts.map +1 -0
  77. package/lib/Deployment.js +62 -0
  78. package/lib/Deployment.js.map +1 -0
  79. package/lib/DeploymentImages.d.ts +18 -0
  80. package/lib/DeploymentImages.d.ts.map +1 -0
  81. package/lib/DeploymentImages.js +61 -0
  82. package/lib/DeploymentImages.js.map +1 -0
  83. package/lib/DeploymentState.d.ts +17 -0
  84. package/lib/DeploymentState.d.ts.map +1 -0
  85. package/lib/DeploymentState.js +87 -0
  86. package/lib/DeploymentState.js.map +1 -0
  87. package/lib/Encrypt.d.ts +50 -0
  88. package/lib/Encrypt.d.ts.map +1 -0
  89. package/lib/Encrypt.js +3 -0
  90. package/lib/Encrypt.js.map +1 -0
  91. package/lib/EncryptHttp.d.ts +22 -0
  92. package/lib/EncryptHttp.d.ts.map +1 -0
  93. package/lib/EncryptHttp.js +39 -0
  94. package/lib/EncryptHttp.js.map +1 -0
  95. package/lib/Environment.d.ts +45 -0
  96. package/lib/Environment.d.ts.map +1 -0
  97. package/lib/Environment.js +43 -0
  98. package/lib/Environment.js.map +1 -0
  99. package/lib/Errors.d.ts +18 -0
  100. package/lib/Errors.d.ts.map +1 -0
  101. package/lib/Errors.js +13 -0
  102. package/lib/Errors.js.map +1 -0
  103. package/lib/Exec.d.ts +41 -0
  104. package/lib/Exec.d.ts.map +1 -0
  105. package/lib/Exec.js +3 -0
  106. package/lib/Exec.js.map +1 -0
  107. package/lib/ExecHttp.d.ts +22 -0
  108. package/lib/ExecHttp.d.ts.map +1 -0
  109. package/lib/ExecHttp.js +39 -0
  110. package/lib/ExecHttp.js.map +1 -0
  111. package/lib/GetObject.d.ts +34 -0
  112. package/lib/GetObject.d.ts.map +1 -0
  113. package/lib/GetObject.js +3 -0
  114. package/lib/GetObject.js.map +1 -0
  115. package/lib/GetObjectHttp.d.ts +12 -0
  116. package/lib/GetObjectHttp.d.ts.map +1 -0
  117. package/lib/GetObjectHttp.js +17 -0
  118. package/lib/GetObjectHttp.js.map +1 -0
  119. package/lib/GetSecret.d.ts +44 -0
  120. package/lib/GetSecret.d.ts.map +1 -0
  121. package/lib/GetSecret.js +3 -0
  122. package/lib/GetSecret.js.map +1 -0
  123. package/lib/GetSecretHttp.d.ts +22 -0
  124. package/lib/GetSecretHttp.d.ts.map +1 -0
  125. package/lib/GetSecretHttp.js +50 -0
  126. package/lib/GetSecretHttp.js.map +1 -0
  127. package/lib/HeadObject.d.ts +29 -0
  128. package/lib/HeadObject.d.ts.map +1 -0
  129. package/lib/HeadObject.js +3 -0
  130. package/lib/HeadObject.js.map +1 -0
  131. package/lib/HeadObjectHttp.d.ts +12 -0
  132. package/lib/HeadObjectHttp.d.ts.map +1 -0
  133. package/lib/HeadObjectHttp.js +17 -0
  134. package/lib/HeadObjectHttp.js.map +1 -0
  135. package/lib/IpAssignment.d.ts +258 -0
  136. package/lib/IpAssignment.d.ts.map +1 -0
  137. package/lib/IpAssignment.js +376 -0
  138. package/lib/IpAssignment.js.map +1 -0
  139. package/lib/ListObjectsV2.d.ts +29 -0
  140. package/lib/ListObjectsV2.d.ts.map +1 -0
  141. package/lib/ListObjectsV2.js +3 -0
  142. package/lib/ListObjectsV2.js.map +1 -0
  143. package/lib/ListObjectsV2Http.d.ts +12 -0
  144. package/lib/ListObjectsV2Http.d.ts.map +1 -0
  145. package/lib/ListObjectsV2Http.js +17 -0
  146. package/lib/ListObjectsV2Http.js.map +1 -0
  147. package/lib/ListSecrets.d.ts +53 -0
  148. package/lib/ListSecrets.d.ts.map +1 -0
  149. package/lib/ListSecrets.js +3 -0
  150. package/lib/ListSecrets.js.map +1 -0
  151. package/lib/ListSecretsHttp.d.ts +22 -0
  152. package/lib/ListSecretsHttp.d.ts.map +1 -0
  153. package/lib/ListSecretsHttp.js +35 -0
  154. package/lib/ListSecretsHttp.js.map +1 -0
  155. package/lib/Machine.d.ts +802 -0
  156. package/lib/Machine.d.ts.map +1 -0
  157. package/lib/Machine.js +773 -0
  158. package/lib/Machine.js.map +1 -0
  159. package/lib/MachineContainers.d.ts +44 -0
  160. package/lib/MachineContainers.d.ts.map +1 -0
  161. package/lib/MachineContainers.js +115 -0
  162. package/lib/MachineContainers.js.map +1 -0
  163. package/lib/Metadata.d.ts +109 -0
  164. package/lib/Metadata.d.ts.map +1 -0
  165. package/lib/Metadata.js +159 -0
  166. package/lib/Metadata.js.map +1 -0
  167. package/lib/MountVolume.d.ts +295 -0
  168. package/lib/MountVolume.d.ts.map +1 -0
  169. package/lib/MountVolume.js +20 -0
  170. package/lib/MountVolume.js.map +1 -0
  171. package/lib/Postgres.d.ts +298 -0
  172. package/lib/Postgres.d.ts.map +1 -0
  173. package/lib/Postgres.js +508 -0
  174. package/lib/Postgres.js.map +1 -0
  175. package/lib/PostgresMigrations.d.ts +35 -0
  176. package/lib/PostgresMigrations.d.ts.map +1 -0
  177. package/lib/PostgresMigrations.js +110 -0
  178. package/lib/PostgresMigrations.js.map +1 -0
  179. package/lib/Providers.d.ts +38 -0
  180. package/lib/Providers.d.ts.map +1 -0
  181. package/lib/Providers.js +95 -0
  182. package/lib/Providers.js.map +1 -0
  183. package/lib/PutObject.d.ts +35 -0
  184. package/lib/PutObject.d.ts.map +1 -0
  185. package/lib/PutObject.js +3 -0
  186. package/lib/PutObject.js.map +1 -0
  187. package/lib/PutObjectHttp.d.ts +12 -0
  188. package/lib/PutObjectHttp.d.ts.map +1 -0
  189. package/lib/PutObjectHttp.js +17 -0
  190. package/lib/PutObjectHttp.js.map +1 -0
  191. package/lib/ReadRedis.d.ts +26 -0
  192. package/lib/ReadRedis.d.ts.map +1 -0
  193. package/lib/ReadRedis.js +3 -0
  194. package/lib/ReadRedis.js.map +1 -0
  195. package/lib/ReadRedisHttp.d.ts +11 -0
  196. package/lib/ReadRedisHttp.d.ts.map +1 -0
  197. package/lib/ReadRedisHttp.js +15 -0
  198. package/lib/ReadRedisHttp.js.map +1 -0
  199. package/lib/ReadWriteRedis.d.ts +29 -0
  200. package/lib/ReadWriteRedis.d.ts.map +1 -0
  201. package/lib/ReadWriteRedis.js +3 -0
  202. package/lib/ReadWriteRedis.js.map +1 -0
  203. package/lib/ReadWriteRedisHttp.d.ts +11 -0
  204. package/lib/ReadWriteRedisHttp.d.ts.map +1 -0
  205. package/lib/ReadWriteRedisHttp.js +15 -0
  206. package/lib/ReadWriteRedisHttp.js.map +1 -0
  207. package/lib/Redis.d.ts +252 -0
  208. package/lib/Redis.d.ts.map +1 -0
  209. package/lib/Redis.js +608 -0
  210. package/lib/Redis.js.map +1 -0
  211. package/lib/RedisBinding.d.ts +7 -0
  212. package/lib/RedisBinding.d.ts.map +1 -0
  213. package/lib/RedisBinding.js +53 -0
  214. package/lib/RedisBinding.js.map +1 -0
  215. package/lib/RedisHttp.d.ts +8 -0
  216. package/lib/RedisHttp.d.ts.map +1 -0
  217. package/lib/RedisHttp.js +8 -0
  218. package/lib/RedisHttp.js.map +1 -0
  219. package/lib/Region.d.ts +16 -0
  220. package/lib/Region.d.ts.map +1 -0
  221. package/lib/Region.js +13 -0
  222. package/lib/Region.js.map +1 -0
  223. package/lib/Secret.d.ts +190 -0
  224. package/lib/Secret.d.ts.map +1 -0
  225. package/lib/Secret.js +310 -0
  226. package/lib/Secret.js.map +1 -0
  227. package/lib/SecretHttp.d.ts +54 -0
  228. package/lib/SecretHttp.d.ts.map +1 -0
  229. package/lib/SecretHttp.js +66 -0
  230. package/lib/SecretHttp.js.map +1 -0
  231. package/lib/SecretKey.d.ts +164 -0
  232. package/lib/SecretKey.d.ts.map +1 -0
  233. package/lib/SecretKey.js +277 -0
  234. package/lib/SecretKey.js.map +1 -0
  235. package/lib/SecretKeyHttp.d.ts +14 -0
  236. package/lib/SecretKeyHttp.d.ts.map +1 -0
  237. package/lib/SecretKeyHttp.js +5 -0
  238. package/lib/SecretKeyHttp.js.map +1 -0
  239. package/lib/Service.d.ts +1022 -0
  240. package/lib/Service.d.ts.map +1 -0
  241. package/lib/Service.js +1397 -0
  242. package/lib/Service.js.map +1 -0
  243. package/lib/Sign.d.ts +36 -0
  244. package/lib/Sign.d.ts.map +1 -0
  245. package/lib/Sign.js +3 -0
  246. package/lib/Sign.js.map +1 -0
  247. package/lib/SignHttp.d.ts +22 -0
  248. package/lib/SignHttp.d.ts.map +1 -0
  249. package/lib/SignHttp.js +36 -0
  250. package/lib/SignHttp.js.map +1 -0
  251. package/lib/Sprite.d.ts +283 -0
  252. package/lib/Sprite.d.ts.map +1 -0
  253. package/lib/Sprite.js +469 -0
  254. package/lib/Sprite.js.map +1 -0
  255. package/lib/SpriteHttp.d.ts +25 -0
  256. package/lib/SpriteHttp.d.ts.map +1 -0
  257. package/lib/SpriteHttp.js +33 -0
  258. package/lib/SpriteHttp.js.map +1 -0
  259. package/lib/Verify.d.ts +37 -0
  260. package/lib/Verify.d.ts.map +1 -0
  261. package/lib/Verify.js +3 -0
  262. package/lib/Verify.js.map +1 -0
  263. package/lib/VerifyHttp.d.ts +22 -0
  264. package/lib/VerifyHttp.d.ts.map +1 -0
  265. package/lib/VerifyHttp.js +38 -0
  266. package/lib/VerifyHttp.js.map +1 -0
  267. package/lib/Volume.d.ts +53 -0
  268. package/lib/Volume.d.ts.map +1 -0
  269. package/lib/Volume.js +188 -0
  270. package/lib/Volume.js.map +1 -0
  271. package/lib/VolumeSnapshot.d.ts +135 -0
  272. package/lib/VolumeSnapshot.d.ts.map +1 -0
  273. package/lib/VolumeSnapshot.js +213 -0
  274. package/lib/VolumeSnapshot.js.map +1 -0
  275. package/lib/Website/AssetDeployment.d.ts +43 -0
  276. package/lib/Website/AssetDeployment.d.ts.map +1 -0
  277. package/lib/Website/AssetDeployment.js +162 -0
  278. package/lib/Website/AssetDeployment.js.map +1 -0
  279. package/lib/Website/Astro.d.ts +87 -0
  280. package/lib/Website/Astro.d.ts.map +1 -0
  281. package/lib/Website/Astro.js +55 -0
  282. package/lib/Website/Astro.js.map +1 -0
  283. package/lib/Website/Foldkit.d.ts +52 -0
  284. package/lib/Website/Foldkit.d.ts.map +1 -0
  285. package/lib/Website/Foldkit.js +45 -0
  286. package/lib/Website/Foldkit.js.map +1 -0
  287. package/lib/Website/FrameworkSite.d.ts +175 -0
  288. package/lib/Website/FrameworkSite.d.ts.map +1 -0
  289. package/lib/Website/FrameworkSite.js +162 -0
  290. package/lib/Website/FrameworkSite.js.map +1 -0
  291. package/lib/Website/Nextjs.d.ts +54 -0
  292. package/lib/Website/Nextjs.d.ts.map +1 -0
  293. package/lib/Website/Nextjs.js +46 -0
  294. package/lib/Website/Nextjs.js.map +1 -0
  295. package/lib/Website/Nuxt.d.ts +51 -0
  296. package/lib/Website/Nuxt.d.ts.map +1 -0
  297. package/lib/Website/Nuxt.js +36 -0
  298. package/lib/Website/Nuxt.js.map +1 -0
  299. package/lib/Website/Octane.d.ts +49 -0
  300. package/lib/Website/Octane.d.ts.map +1 -0
  301. package/lib/Website/Octane.js +39 -0
  302. package/lib/Website/Octane.js.map +1 -0
  303. package/lib/Website/ReactRouter.d.ts +80 -0
  304. package/lib/Website/ReactRouter.d.ts.map +1 -0
  305. package/lib/Website/ReactRouter.js +70 -0
  306. package/lib/Website/ReactRouter.js.map +1 -0
  307. package/lib/Website/SolidStart.d.ts +93 -0
  308. package/lib/Website/SolidStart.d.ts.map +1 -0
  309. package/lib/Website/SolidStart.js +71 -0
  310. package/lib/Website/SolidStart.js.map +1 -0
  311. package/lib/Website/StaticSite.d.ts +155 -0
  312. package/lib/Website/StaticSite.d.ts.map +1 -0
  313. package/lib/Website/StaticSite.js +168 -0
  314. package/lib/Website/StaticSite.js.map +1 -0
  315. package/lib/Website/SvelteKit.d.ts +52 -0
  316. package/lib/Website/SvelteKit.d.ts.map +1 -0
  317. package/lib/Website/SvelteKit.js +37 -0
  318. package/lib/Website/SvelteKit.js.map +1 -0
  319. package/lib/Website/TanStackStart.d.ts +76 -0
  320. package/lib/Website/TanStackStart.d.ts.map +1 -0
  321. package/lib/Website/TanStackStart.js +66 -0
  322. package/lib/Website/TanStackStart.js.map +1 -0
  323. package/lib/Website/Vinext.d.ts +73 -0
  324. package/lib/Website/Vinext.d.ts.map +1 -0
  325. package/lib/Website/Vinext.js +67 -0
  326. package/lib/Website/Vinext.js.map +1 -0
  327. package/lib/Website/Vite.d.ts +103 -0
  328. package/lib/Website/Vite.d.ts.map +1 -0
  329. package/lib/Website/Vite.js +91 -0
  330. package/lib/Website/Vite.js.map +1 -0
  331. package/lib/Website/Vocs.d.ts +52 -0
  332. package/lib/Website/Vocs.d.ts.map +1 -0
  333. package/lib/Website/Vocs.js +38 -0
  334. package/lib/Website/Vocs.js.map +1 -0
  335. package/lib/Website/Waku.d.ts +64 -0
  336. package/lib/Website/Waku.d.ts.map +1 -0
  337. package/lib/Website/Waku.js +39 -0
  338. package/lib/Website/Waku.js.map +1 -0
  339. package/lib/Website/index.d.ts +17 -0
  340. package/lib/Website/index.d.ts.map +1 -0
  341. package/lib/Website/index.js +17 -0
  342. package/lib/Website/index.js.map +1 -0
  343. package/lib/WriteCertificates.d.ts +63 -0
  344. package/lib/WriteCertificates.d.ts.map +1 -0
  345. package/lib/WriteCertificates.js +3 -0
  346. package/lib/WriteCertificates.js.map +1 -0
  347. package/lib/WriteCertificatesHttp.d.ts +25 -0
  348. package/lib/WriteCertificatesHttp.d.ts.map +1 -0
  349. package/lib/WriteCertificatesHttp.js +67 -0
  350. package/lib/WriteCertificatesHttp.js.map +1 -0
  351. package/lib/WriteRedis.d.ts +26 -0
  352. package/lib/WriteRedis.d.ts.map +1 -0
  353. package/lib/WriteRedis.js +3 -0
  354. package/lib/WriteRedis.js.map +1 -0
  355. package/lib/WriteRedisHttp.d.ts +11 -0
  356. package/lib/WriteRedisHttp.d.ts.map +1 -0
  357. package/lib/WriteRedisHttp.js +15 -0
  358. package/lib/WriteRedisHttp.js.map +1 -0
  359. package/lib/WriteSecret.d.ts +68 -0
  360. package/lib/WriteSecret.d.ts.map +1 -0
  361. package/lib/WriteSecret.js +4 -0
  362. package/lib/WriteSecret.js.map +1 -0
  363. package/lib/WriteSecretHttp.d.ts +26 -0
  364. package/lib/WriteSecretHttp.d.ts.map +1 -0
  365. package/lib/WriteSecretHttp.js +54 -0
  366. package/lib/WriteSecretHttp.js.map +1 -0
  367. package/lib/bluegreen.d.ts +36 -0
  368. package/lib/bluegreen.d.ts.map +1 -0
  369. package/lib/bluegreen.js +458 -0
  370. package/lib/bluegreen.js.map +1 -0
  371. package/lib/hosted.d.ts +172 -0
  372. package/lib/hosted.d.ts.map +1 -0
  373. package/lib/hosted.js +458 -0
  374. package/lib/hosted.js.map +1 -0
  375. package/lib/index.d.ts +65 -0
  376. package/lib/index.d.ts.map +1 -0
  377. package/lib/index.js +63 -0
  378. package/lib/index.js.map +1 -0
  379. package/lib/internal/RemoteBuilder.d.ts +28 -0
  380. package/lib/internal/RemoteBuilder.d.ts.map +1 -0
  381. package/lib/internal/RemoteBuilder.js +145 -0
  382. package/lib/internal/RemoteBuilder.js.map +1 -0
  383. package/lib/leases.d.ts +53 -0
  384. package/lib/leases.d.ts.map +1 -0
  385. package/lib/leases.js +279 -0
  386. package/lib/leases.js.map +1 -0
  387. package/lib/ports.d.ts +51 -0
  388. package/lib/ports.d.ts.map +1 -0
  389. package/lib/ports.js +123 -0
  390. package/lib/ports.js.map +1 -0
  391. package/lib/replicas.d.ts +270 -0
  392. package/lib/replicas.d.ts.map +1 -0
  393. package/lib/replicas.js +969 -0
  394. package/lib/replicas.js.map +1 -0
  395. package/lib/rpc.d.ts +35 -0
  396. package/lib/rpc.d.ts.map +1 -0
  397. package/lib/rpc.js +113 -0
  398. package/lib/rpc.js.map +1 -0
  399. package/package.json +83 -3
  400. package/src/App.ts +516 -0
  401. package/src/AuthProvider.ts +68 -0
  402. package/src/BindService.ts +304 -0
  403. package/src/Bootstrap.ts +66 -0
  404. package/src/Bucket.ts +916 -0
  405. package/src/BucketBinding.ts +128 -0
  406. package/src/Catalog.ts +43 -0
  407. package/src/Certificate.ts +548 -0
  408. package/src/Checkpoint.ts +69 -0
  409. package/src/CheckpointHttp.ts +66 -0
  410. package/src/ConnectPostgres.ts +68 -0
  411. package/src/ConnectPostgresHttp.ts +77 -0
  412. package/src/Contributions.ts +9 -0
  413. package/src/Credentials.ts +102 -0
  414. package/src/Decrypt.ts +62 -0
  415. package/src/DecryptHttp.ts +52 -0
  416. package/src/DeleteObject.ts +43 -0
  417. package/src/DeleteObjectHttp.ts +20 -0
  418. package/src/Deployment.ts +121 -0
  419. package/src/DeploymentImages.ts +84 -0
  420. package/src/DeploymentState.ts +104 -0
  421. package/src/Encrypt.ts +60 -0
  422. package/src/EncryptHttp.ts +48 -0
  423. package/src/Environment.ts +81 -0
  424. package/src/Errors.ts +14 -0
  425. package/src/Exec.ts +50 -0
  426. package/src/ExecHttp.ts +47 -0
  427. package/src/GetObject.ts +48 -0
  428. package/src/GetObjectHttp.ts +20 -0
  429. package/src/GetSecret.ts +48 -0
  430. package/src/GetSecretHttp.ts +60 -0
  431. package/src/HeadObject.ts +43 -0
  432. package/src/HeadObjectHttp.ts +20 -0
  433. package/src/IpAssignment.ts +522 -0
  434. package/src/ListObjectsV2.ts +43 -0
  435. package/src/ListObjectsV2Http.ts +20 -0
  436. package/src/ListSecrets.ts +57 -0
  437. package/src/ListSecretsHttp.ts +43 -0
  438. package/src/Machine.ts +1268 -0
  439. package/src/MachineContainers.ts +152 -0
  440. package/src/Metadata.ts +195 -0
  441. package/src/MountVolume.ts +315 -0
  442. package/src/Postgres.ts +777 -0
  443. package/src/PostgresMigrations.ts +153 -0
  444. package/src/Providers.ts +155 -0
  445. package/src/PutObject.ts +49 -0
  446. package/src/PutObjectHttp.ts +20 -0
  447. package/src/ReadRedis.ts +31 -0
  448. package/src/ReadRedisHttp.ts +18 -0
  449. package/src/ReadWriteRedis.ts +33 -0
  450. package/src/ReadWriteRedisHttp.ts +18 -0
  451. package/src/Redis.ts +820 -0
  452. package/src/RedisBinding.ts +64 -0
  453. package/src/RedisHttp.ts +11 -0
  454. package/src/Region.ts +44 -0
  455. package/src/Secret.ts +405 -0
  456. package/src/SecretHttp.ts +149 -0
  457. package/src/SecretKey.ts +389 -0
  458. package/src/SecretKeyHttp.ts +23 -0
  459. package/src/Service.ts +1934 -0
  460. package/src/Sign.ts +46 -0
  461. package/src/SignHttp.ts +44 -0
  462. package/src/Sprite.ts +671 -0
  463. package/src/SpriteHttp.ts +50 -0
  464. package/src/Verify.ts +47 -0
  465. package/src/VerifyHttp.ts +46 -0
  466. package/src/Volume.ts +264 -0
  467. package/src/VolumeSnapshot.ts +321 -0
  468. package/src/Website/AssetDeployment.ts +294 -0
  469. package/src/Website/Astro.ts +87 -0
  470. package/src/Website/Foldkit.ts +54 -0
  471. package/src/Website/FrameworkSite.ts +363 -0
  472. package/src/Website/Nextjs.ts +50 -0
  473. package/src/Website/Nuxt.ts +48 -0
  474. package/src/Website/Octane.ts +44 -0
  475. package/src/Website/ReactRouter.ts +76 -0
  476. package/src/Website/SolidStart.ts +90 -0
  477. package/src/Website/StaticSite.ts +275 -0
  478. package/src/Website/SvelteKit.ts +49 -0
  479. package/src/Website/TanStackStart.ts +72 -0
  480. package/src/Website/Vinext.ts +79 -0
  481. package/src/Website/Vite.ts +112 -0
  482. package/src/Website/Vocs.ts +50 -0
  483. package/src/Website/Waku.ts +65 -0
  484. package/src/Website/index.ts +16 -0
  485. package/src/WriteCertificates.ts +90 -0
  486. package/src/WriteCertificatesHttp.ts +93 -0
  487. package/src/WriteRedis.ts +31 -0
  488. package/src/WriteRedisHttp.ts +18 -0
  489. package/src/WriteSecret.ts +86 -0
  490. package/src/WriteSecretHttp.ts +71 -0
  491. package/src/bluegreen.ts +708 -0
  492. package/src/globals.d.ts +2 -0
  493. package/src/hosted.ts +668 -0
  494. package/src/index.ts +64 -0
  495. package/src/internal/RemoteBuilder.ts +224 -0
  496. package/src/leases.ts +437 -0
  497. package/src/ports.ts +177 -0
  498. package/src/replicas.ts +1480 -0
  499. package/src/rpc.ts +136 -0
package/src/Bucket.ts ADDED
@@ -0,0 +1,916 @@
1
+ import type { AddOnsResponseEdgesItemNode } from "@distilled.cloud/fly-io/addons";
2
+ import * as addons from "@distilled.cloud/fly-io/addons";
3
+ import * as machines from "@distilled.cloud/fly-io/machines";
4
+ import { Unowned } from "alchemy/AdoptPolicy";
5
+ import { deepEqual, isResolved } from "alchemy/Diff";
6
+ import * as Provider from "alchemy/Provider";
7
+ import { Resource } from "alchemy/Resource";
8
+ import { createInternalTags } from "alchemy/Tags";
9
+ import * as Data from "effect/Data";
10
+ import * as Duration from "effect/Duration";
11
+ import * as Effect from "effect/Effect";
12
+ import * as Redacted from "effect/Redacted";
13
+ import * as Result from "effect/Result";
14
+ import * as Schedule from "effect/Schedule";
15
+ import { resolveOrgSlug } from "./Environment.ts";
16
+ import { TigrisCredentialsMissing } from "./Errors.ts";
17
+ import { createFlyAppName, matchesAlchemyPhysicalName } from "./Metadata.ts";
18
+ import type { Providers } from "./Providers.ts";
19
+
20
+ /** Env-var names Tigris HTTP bindings write onto an App (same as `fly storage create`). */
21
+ export const BUCKET_SECRET_NAMES = [
22
+ "AWS_ACCESS_KEY_ID",
23
+ "AWS_SECRET_ACCESS_KEY",
24
+ "AWS_ENDPOINT_URL_S3",
25
+ "AWS_REGION",
26
+ "BUCKET_NAME",
27
+ ] as const;
28
+
29
+ export type BucketSecretName = (typeof BUCKET_SECRET_NAMES)[number];
30
+
31
+ /**
32
+ * Shadow bucket used to migrate from another S3-compatible store.
33
+ * Every field is required when set.
34
+ */
35
+ export interface BucketShadow {
36
+ /** Shadow-bucket access key id. */
37
+ accessKey: string;
38
+ /** Shadow-bucket secret. Wrap with `Redacted.make`. */
39
+ secretKey: Redacted.Redacted<string> | string;
40
+ /** Shadow-bucket region. */
41
+ region: string;
42
+ /** Shadow-bucket name. */
43
+ name: string;
44
+ /** Shadow-bucket S3 endpoint URL. */
45
+ endpoint: string;
46
+ /**
47
+ * Dual-write new objects back to the shadow bucket.
48
+ *
49
+ * @default false
50
+ */
51
+ writeThrough?: boolean;
52
+ }
53
+
54
+ export interface BucketProps {
55
+ /**
56
+ * Tigris bucket / add-on name. Globally unique, DNS-compatible
57
+ * (lowercase letters, digits, hyphens), must start with a letter,
58
+ * max 63 characters. If omitted, a unique name is generated from
59
+ * the stack, stage and logical ID. Changing it replaces the Bucket.
60
+ */
61
+ name?: string;
62
+ /**
63
+ * Organization slug. Defaults to the current token's org
64
+ * (`getCurrentToken`). Changing it replaces the Bucket.
65
+ */
66
+ orgSlug?: string;
67
+ /**
68
+ * Serve objects without credentials. Default is private.
69
+ *
70
+ * @default false
71
+ */
72
+ public?: boolean;
73
+ /**
74
+ * Custom domain for public website hosting. Maps to Tigris
75
+ * `options.website.domain_name`. Empty string when omitted
76
+ * (the Tigris API requires the field).
77
+ */
78
+ domainName?: string;
79
+ /**
80
+ * Tigris accelerate. Default is off.
81
+ *
82
+ * @default false
83
+ */
84
+ accelerate?: boolean;
85
+ /**
86
+ * Shadow bucket for zero-downtime migration from another
87
+ * S3-compatible store. Every nested field is required when set.
88
+ */
89
+ shadowBucket?: BucketShadow;
90
+ }
91
+
92
+ export type Bucket = Resource<
93
+ "Fly.Bucket",
94
+ BucketProps,
95
+ {
96
+ /** Fly GraphQL add-on id. Identity of the Bucket. */
97
+ addOnId: string;
98
+ /** Physical Tigris add-on / bucket name. */
99
+ name: string;
100
+ /** Observed provisioning status (`ready`, …). */
101
+ status: string | undefined;
102
+ /** Organization slug. */
103
+ orgSlug: string | undefined;
104
+ /** Whether the bucket is public. */
105
+ public: boolean;
106
+ /** Custom website domain, if set. */
107
+ domainName: string | undefined;
108
+ /** Tigris accelerate. */
109
+ accelerate: boolean;
110
+ /** Tigris SSO dashboard URL, if the API returned one. */
111
+ ssoLink: string | undefined;
112
+ /** RFC3339 creation timestamp. */
113
+ createdAt: string | undefined;
114
+ /**
115
+ * `AWS_ACCESS_KEY_ID` from `createAddOn.environment`. Never logged.
116
+ */
117
+ accessKeyId: Redacted.Redacted<string> | undefined;
118
+ /**
119
+ * `AWS_SECRET_ACCESS_KEY` from `createAddOn.environment`. Never logged.
120
+ */
121
+ secretAccessKey: Redacted.Redacted<string> | undefined;
122
+ /**
123
+ * `AWS_ENDPOINT_URL_S3` from `createAddOn.environment`. Never logged.
124
+ */
125
+ endpoint: Redacted.Redacted<string> | undefined;
126
+ /**
127
+ * `AWS_REGION` from `createAddOn.environment`. Never logged.
128
+ */
129
+ region: Redacted.Redacted<string> | undefined;
130
+ /**
131
+ * `BUCKET_NAME` from `createAddOn.environment`. Never logged.
132
+ */
133
+ bucketName: Redacted.Redacted<string> | undefined;
134
+ },
135
+ never,
136
+ Providers
137
+ >;
138
+
139
+ /**
140
+ * A Fly.Bucket is Tigris S3-compatible object storage, billed through
141
+ * Fly. It is an org-scoped GraphQL add-on (`AddOnType` `tigris`).
142
+ *
143
+ * @see https://fly.io/docs/tigris/
144
+ *
145
+ * ### Create a Bucket
146
+ * Alchemy generates a unique name unless you pass one.
147
+ *
148
+ * **Example:** Generated name
149
+ * ```typescript
150
+ * const data = yield* Fly.Bucket("Data");
151
+ * ```
152
+ *
153
+ * ### A stable name
154
+ * Pass `name` when you need a stable Tigris bucket name.
155
+ *
156
+ * **Example:** Explicit name
157
+ * ```typescript
158
+ * const data = yield* Fly.Bucket("Data", {
159
+ * name: "my-bucket",
160
+ * });
161
+ * ```
162
+ *
163
+ * :::caution[Changing `name` replaces the Bucket]
164
+ * Tigris cannot rename a bucket. Alchemy creates the new name, then
165
+ * deletes the old one.
166
+ * :::
167
+ *
168
+ * ### Organization
169
+ * Org defaults to the current token. Pass `orgSlug` to pin it.
170
+ *
171
+ * **Example:** Pin an org
172
+ * ```typescript
173
+ * const data = yield* Fly.Bucket("Data", {
174
+ * orgSlug: "my-org",
175
+ * });
176
+ * ```
177
+ *
178
+ * :::caution[Changing `orgSlug` replaces the Bucket]
179
+ * The bucket is created in the new org. The old bucket is deleted.
180
+ * :::
181
+ *
182
+ * ### Public access
183
+ * Buckets are private by default. `public: true` serves objects
184
+ * without credentials.
185
+ *
186
+ * **Example:** Public bucket
187
+ * ```typescript
188
+ * const assets = yield* Fly.Bucket("Assets", {
189
+ * public: true,
190
+ * });
191
+ * ```
192
+ *
193
+ * ### Custom domain
194
+ * `domainName` sets `website.domain_name` on the add-on. Point a
195
+ * CNAME at `{name}.t3.tigrisbucket.io`.
196
+ *
197
+ * **Example:** Custom domain
198
+ * ```typescript
199
+ * const assets = yield* Fly.Bucket("Assets", {
200
+ * public: true,
201
+ * domainName: "assets.example.com",
202
+ * });
203
+ * ```
204
+ *
205
+ * ### Put and get objects
206
+ * Tigris speaks the S3 API. Bind {@link PutObject} / {@link GetObject}
207
+ * (and the other S3 object ops) in Service init. Alchemy injects the
208
+ * Tigris endpoint and credentials; you never read `AWS_*` yourself.
209
+ *
210
+ * **Example:** Put an object from a Service
211
+ * ```typescript
212
+ * import * as HttpServerResponse from "effect/http/HttpServerResponse";
213
+ *
214
+ * export default class Api extends Fly.Service<Api>()(
215
+ * "Api",
216
+ * { app: Site, main: import.meta.url, port: 3000 },
217
+ * Effect.gen(function* () {
218
+ * const putObject = yield* Fly.PutObject(Data);
219
+ * const getObject = yield* Fly.GetObject(Data);
220
+ *
221
+ * return {
222
+ * fetch: Effect.gen(function* () {
223
+ * yield* putObject({
224
+ * Key: "hello.txt",
225
+ * Body: "hello",
226
+ * ContentType: "text/plain",
227
+ * });
228
+ * const obj = yield* getObject({ Key: "hello.txt" });
229
+ * return HttpServerResponse.json({ ok: obj.ETag !== undefined });
230
+ * }),
231
+ * };
232
+ * }).pipe(Effect.provide([Fly.PutObjectHttp, Fly.GetObjectHttp])),
233
+ * ) {}
234
+ * ```
235
+ *
236
+ * ### Fly.Secret
237
+ * You can also set each key yourself with {@link Secret}.
238
+ *
239
+ * **Example:** Manual secrets
240
+ * ```typescript
241
+ * yield* Fly.Secret("BucketName", {
242
+ * app: Site,
243
+ * name: "BUCKET_NAME",
244
+ * value: Data.bucketName,
245
+ * });
246
+ * ```
247
+ *
248
+ * @resource
249
+ * @product Bucket
250
+ */
251
+ export const Bucket = Resource<Bucket>("Fly.Bucket");
252
+
253
+ export class BucketNotCreated extends Data.TaggedError("Fly.BucketNotCreated")<{
254
+ name: string;
255
+ }> {}
256
+
257
+ export class BucketOrgMissing extends Data.TaggedError("Fly.BucketOrgMissing")<{
258
+ orgSlug: string;
259
+ }> {}
260
+
261
+ export class BucketProvisionFailed extends Data.TaggedError("Fly.BucketProvisionFailed")<{
262
+ name: string;
263
+ status: string | undefined;
264
+ errorMessage: string | undefined;
265
+ }> {}
266
+
267
+ class BucketPending extends Data.TaggedError("Fly.BucketPending")<{
268
+ name: string;
269
+ status: string;
270
+ }> {}
271
+
272
+ const TIGRIS = "tigris" as const;
273
+
274
+ const backoff = Schedule.min([
275
+ Schedule.exponential(Duration.millis(500), 1.5),
276
+ Schedule.spaced(Duration.seconds(5)),
277
+ ]);
278
+
279
+ const sanitizeFlyBucketName = (name: string): string => {
280
+ const lowered = name
281
+ .toLowerCase()
282
+ .replace(/[^a-z0-9-]+/g, "-")
283
+ .replace(/-+/g, "-")
284
+ .replace(/^-+|-+$/g, "");
285
+ const clipped = lowered.length > 63 ? lowered.slice(0, 63).replace(/-+$/g, "") : lowered;
286
+ const raw = clipped.length === 0 ? "f" : clipped;
287
+ return /^[a-z]/.test(raw) ? raw : `f${raw}`.slice(0, 63);
288
+ };
289
+
290
+ const resolveBucketName = (id: string, name: string | undefined, existing?: string) =>
291
+ Effect.gen(function* () {
292
+ if (name !== undefined) return sanitizeFlyBucketName(name);
293
+ if (existing !== undefined) return existing;
294
+ return yield* createFlyAppName(id);
295
+ });
296
+
297
+ const asRecord = (value: unknown): Record<string, unknown> => {
298
+ if (Redacted.isRedacted(value)) {
299
+ return value.pipe(Redacted.value, asRecord);
300
+ }
301
+ if (typeof value === "string") {
302
+ try {
303
+ return asRecord(JSON.parse(value));
304
+ } catch {
305
+ return {};
306
+ }
307
+ }
308
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
309
+ return value as Record<string, unknown>;
310
+ }
311
+ return {};
312
+ };
313
+
314
+ const asString = (value: unknown): string | undefined => {
315
+ if (typeof value === "string") {
316
+ return value.length > 0 ? value : undefined;
317
+ }
318
+ if (Redacted.isRedacted(value)) {
319
+ return value.pipe(Redacted.value, asString);
320
+ }
321
+ return undefined;
322
+ };
323
+
324
+ const redact = (value: string | undefined): Redacted.Redacted<string> | undefined =>
325
+ value !== undefined && value.length > 0 ? Redacted.make(value) : undefined;
326
+
327
+ const keepSecret = (
328
+ next: Redacted.Redacted<string> | undefined,
329
+ previous: Redacted.Redacted<string> | undefined,
330
+ ): Redacted.Redacted<string> | undefined => next ?? previous;
331
+
332
+ const envString = (env: Record<string, unknown>, key: BucketSecretName): string | undefined =>
333
+ asString(env[key]);
334
+
335
+ type ObservedAddOn = Pick<
336
+ AddOnsResponseEdgesItemNode,
337
+ | "id"
338
+ | "name"
339
+ | "status"
340
+ | "errorMessage"
341
+ | "environment"
342
+ | "options"
343
+ | "metadata"
344
+ | "ssoLink"
345
+ | "createdAt"
346
+ > & {
347
+ organization?: { slug?: string | null; rawSlug?: string } | null;
348
+ };
349
+
350
+ const unwrapSecret = (value: Redacted.Redacted<string> | string): string =>
351
+ Redacted.isRedacted(value) ? Redacted.value(value) : value;
352
+
353
+ const desiredOptions = (props: BucketProps): Record<string, unknown> => {
354
+ const options: Record<string, unknown> = {
355
+ public: props.public ?? false,
356
+ accelerate: props.accelerate ?? false,
357
+ website: { domain_name: props.domainName ?? "" },
358
+ };
359
+ if (props.shadowBucket !== undefined) {
360
+ options.shadow_bucket = {
361
+ access_key: props.shadowBucket.accessKey,
362
+ secret_key: unwrapSecret(props.shadowBucket.secretKey),
363
+ region: props.shadowBucket.region,
364
+ name: props.shadowBucket.name,
365
+ endpoint: props.shadowBucket.endpoint,
366
+ write_through: props.shadowBucket.writeThrough ?? false,
367
+ };
368
+ }
369
+ return options;
370
+ };
371
+
372
+ const websiteDomain = (options: Record<string, unknown>): string | undefined => {
373
+ const website = asRecord(options.website);
374
+ return asString(website.domain_name);
375
+ };
376
+
377
+ const toAttrs = (
378
+ addOn: ObservedAddOn,
379
+ previous?: Bucket["Attributes"],
380
+ fallback?: { name?: string; orgSlug?: string },
381
+ ): Bucket["Attributes"] => {
382
+ const options = asRecord(addOn.options);
383
+ const env = asRecord(addOn.environment);
384
+ const name = addOn.name ?? fallback?.name ?? previous?.name ?? "";
385
+ const orgSlug =
386
+ asString(addOn.organization?.slug) ??
387
+ asString(addOn.organization?.rawSlug) ??
388
+ fallback?.orgSlug ??
389
+ previous?.orgSlug;
390
+ return {
391
+ addOnId: addOn.id,
392
+ name,
393
+ status: addOn.status ?? undefined,
394
+ orgSlug,
395
+ public: typeof options.public === "boolean" ? options.public : (previous?.public ?? false),
396
+ domainName: websiteDomain(options),
397
+ accelerate: options.accelerate === true,
398
+ ssoLink: addOn.ssoLink ?? undefined,
399
+ createdAt: addOn.createdAt,
400
+ accessKeyId: keepSecret(redact(envString(env, "AWS_ACCESS_KEY_ID")), previous?.accessKeyId),
401
+ secretAccessKey: keepSecret(
402
+ redact(envString(env, "AWS_SECRET_ACCESS_KEY")),
403
+ previous?.secretAccessKey,
404
+ ),
405
+ endpoint: keepSecret(redact(envString(env, "AWS_ENDPOINT_URL_S3")), previous?.endpoint),
406
+ region: keepSecret(redact(envString(env, "AWS_REGION")), previous?.region),
407
+ bucketName: keepSecret(redact(envString(env, "BUCKET_NAME") ?? name), previous?.bucketName),
408
+ };
409
+ };
410
+
411
+ const stringRecordOf = (value: unknown): Record<string, string> =>
412
+ Object.fromEntries(
413
+ Object.entries(asRecord(value)).flatMap(([key, item]) => {
414
+ const text = asString(item);
415
+ return text !== undefined ? [[key, text]] : [];
416
+ }),
417
+ );
418
+
419
+ const hasAlchemyMetadata = (metadata: unknown): boolean => {
420
+ const tags = stringRecordOf(metadata);
421
+ const stack = tags["alchemy::stack"] ?? tags["alchemy.stack"];
422
+ return stack !== undefined && stack.length > 0;
423
+ };
424
+
425
+ const isOwnedAddOn = (addOn: ObservedAddOn): boolean =>
426
+ matchesAlchemyPhysicalName(addOn.name ?? undefined) || hasAlchemyMetadata(addOn.metadata);
427
+
428
+ export const listTigrisAddOns = Effect.fn(function* () {
429
+ const rows: AddOnsResponseEdgesItemNode[] = [];
430
+ let after: string | undefined;
431
+ for (let i = 0; i < 8; i++) {
432
+ const page = yield* addons.addOns({
433
+ type: TIGRIS,
434
+ first: 50,
435
+ after,
436
+ });
437
+ for (const edge of page.edges ?? []) {
438
+ if (edge?.node != null) rows.push(edge.node);
439
+ }
440
+ if (!page.pageInfo.hasNextPage) break;
441
+ after = page.pageInfo.endCursor ?? undefined;
442
+ if (after === undefined || after.length === 0) break;
443
+ }
444
+ return rows;
445
+ });
446
+
447
+ const findById = (addOnId: string) =>
448
+ listTigrisAddOns().pipe(Effect.map((addOns) => addOns.find((addOn) => addOn.id === addOnId)));
449
+
450
+ const findByName = (name: string) =>
451
+ listTigrisAddOns().pipe(Effect.map((addOns) => addOns.find((addOn) => addOn.name === name)));
452
+
453
+ const failedStatus = (status: string | undefined) => status === "error" || status === "failed";
454
+
455
+ const pendingStatus = (status: string | undefined) =>
456
+ status === "creating" ||
457
+ status === "provisioning" ||
458
+ status === "pending" ||
459
+ status === "pending_create";
460
+
461
+ const waitUntilReady = (name: string, addOnId: string) =>
462
+ findById(addOnId).pipe(
463
+ Effect.flatMap(
464
+ (
465
+ addOn,
466
+ ): Effect.Effect<AddOnsResponseEdgesItemNode, BucketPending | BucketProvisionFailed> => {
467
+ if (addOn === undefined) {
468
+ return Effect.fail(new BucketPending({ name, status: "missing" }));
469
+ }
470
+ const status = addOn.status ?? undefined;
471
+ if (failedStatus(status)) {
472
+ return Effect.fail(
473
+ new BucketProvisionFailed({
474
+ name,
475
+ status,
476
+ errorMessage: addOn.errorMessage ?? undefined,
477
+ }),
478
+ );
479
+ }
480
+ if (pendingStatus(status)) {
481
+ return Effect.fail(new BucketPending({ name, status: status ?? "creating" }));
482
+ }
483
+ return Effect.succeed(addOn);
484
+ },
485
+ ),
486
+ Effect.retry({
487
+ while: (e) => e._tag === "Fly.BucketPending",
488
+ times: 8,
489
+ schedule: backoff,
490
+ }),
491
+ Effect.catchTag("Fly.BucketPending", () => findById(addOnId)),
492
+ );
493
+
494
+ const waitUntilGone = (addOnId: string, name: string) =>
495
+ Effect.gen(function* () {
496
+ // Best-effort: Tigris often answers "The specified bucket does not
497
+ // exist" (untyped UnknownFlyIoError) for a delete that already
498
+ // succeeded. Never fail the wait on that — only on the add-on still
499
+ // showing up in list.
500
+ yield* Effect.result(
501
+ addons.deleteAddOn({
502
+ input: addOnId.length > 0 ? { addOnId } : { name, provider: TIGRIS },
503
+ }),
504
+ );
505
+ const still =
506
+ (yield* findById(addOnId)) ?? (name.length > 0 ? yield* findByName(name) : undefined);
507
+ if (still !== undefined) {
508
+ return yield* new BucketPending({
509
+ name,
510
+ status: still.status ?? "deleting",
511
+ });
512
+ }
513
+ }).pipe(
514
+ Effect.retry({
515
+ while: (e) => e._tag === "Fly.BucketPending",
516
+ schedule: Schedule.spaced("2 seconds"),
517
+ times: 20,
518
+ }),
519
+ );
520
+
521
+ const resolveOrganization = (orgSlug: string) =>
522
+ addons
523
+ .organization({ slug: orgSlug })
524
+ .pipe(Effect.catchTag("FlyIoParseError", () => Effect.succeed(undefined)));
525
+
526
+ const ensureTos = (orgSlug: string, organizationId: string) =>
527
+ Effect.gen(function* () {
528
+ const agreed = yield* addons.agreedToProviderTos({
529
+ slug: orgSlug,
530
+ providerName: TIGRIS,
531
+ });
532
+ if (agreed === true) return;
533
+ const tos = yield* Effect.result(
534
+ addons.createExtensionTosAgreement({
535
+ input: {
536
+ addOnProviderName: TIGRIS,
537
+ organizationId,
538
+ },
539
+ }),
540
+ );
541
+ if (Result.isFailure(tos)) return;
542
+ });
543
+
544
+ const optionsEqual = (
545
+ observed: Record<string, unknown>,
546
+ desired: Record<string, unknown>,
547
+ ): boolean => {
548
+ const observedPublic = observed.public === true;
549
+ const desiredPublic = desired.public === true;
550
+ const observedAccelerate = observed.accelerate === true;
551
+ const desiredAccelerate = desired.accelerate === true;
552
+ const observedDomain = websiteDomain(observed) ?? "";
553
+ const desiredDomain = websiteDomain(desired) ?? "";
554
+ if (
555
+ observedPublic !== desiredPublic ||
556
+ observedAccelerate !== desiredAccelerate ||
557
+ observedDomain !== desiredDomain
558
+ ) {
559
+ return false;
560
+ }
561
+ if (desired.shadow_bucket !== undefined) {
562
+ return deepEqual(asRecord(observed.shadow_bucket), desired.shadow_bucket);
563
+ }
564
+ return true;
565
+ };
566
+
567
+ export const BucketProvider = () =>
568
+ Provider.succeed(Bucket, {
569
+ stables: ["addOnId", "name", "orgSlug"],
570
+
571
+ diff: Effect.fn(function* ({ news, output }) {
572
+ if (news === undefined || !isResolved(news)) return undefined;
573
+ if (output === undefined) return undefined;
574
+ const desiredName = news.name !== undefined ? sanitizeFlyBucketName(news.name) : output.name;
575
+ const nameChanged = desiredName !== output.name;
576
+ const orgChanged = news.orgSlug !== undefined && news.orgSlug !== output.orgSlug;
577
+ if (nameChanged || orgChanged) {
578
+ return { action: "replace" as const };
579
+ }
580
+ return undefined;
581
+ }),
582
+
583
+ read: Effect.fn(function* ({ id, olds, output }) {
584
+ const name = yield* resolveBucketName(id, olds?.name, output?.name);
585
+ const found =
586
+ (output?.addOnId !== undefined && output.addOnId.length > 0
587
+ ? yield* findById(output.addOnId)
588
+ : undefined) ?? (yield* findByName(name));
589
+ if (found === undefined) return undefined;
590
+ const attrs = toAttrs(found, output, {
591
+ name,
592
+ orgSlug: output?.orgSlug ?? olds?.orgSlug,
593
+ });
594
+ if (output !== undefined) return attrs;
595
+ return isOwnedAddOn(found) ? attrs : Unowned(attrs);
596
+ }),
597
+
598
+ list: Effect.fn(function* () {
599
+ const addOns = yield* listTigrisAddOns();
600
+ return addOns.flatMap((addOn) => (isOwnedAddOn(addOn) ? [toAttrs(addOn)] : []));
601
+ }),
602
+
603
+ reconcile: Effect.fn(function* ({ id, news, output }) {
604
+ const props = news ?? ({} as BucketProps);
605
+ const name = yield* resolveBucketName(id, props.name, output?.name);
606
+ const orgSlug = props.orgSlug ?? output?.orgSlug ?? (yield* resolveOrgSlug());
607
+ let previous = output;
608
+
609
+ // Observe by cached id, then the desired name.
610
+ let current: ObservedAddOn | undefined =
611
+ output?.addOnId !== undefined && output.addOnId.length > 0
612
+ ? yield* findById(output.addOnId)
613
+ : undefined;
614
+ if (current === undefined) {
615
+ current = yield* findByName(name);
616
+ }
617
+
618
+ const org = yield* resolveOrganization(orgSlug);
619
+ if (org === undefined) {
620
+ return yield* new BucketOrgMissing({ orgSlug });
621
+ }
622
+
623
+ if (current === undefined) {
624
+ yield* ensureTos(orgSlug, org.id);
625
+ const created = yield* Effect.result(
626
+ addons.createAddOn({
627
+ input: {
628
+ type: TIGRIS,
629
+ name,
630
+ organizationId: org.id,
631
+ options: desiredOptions(props),
632
+ },
633
+ }),
634
+ );
635
+ if (Result.isSuccess(created)) {
636
+ current = created.success.addOn;
637
+ } else {
638
+ current = yield* findByName(name);
639
+ if (current === undefined) {
640
+ return yield* created.failure;
641
+ }
642
+ }
643
+ const createdSecrets = current;
644
+ if (current.id.length > 0) {
645
+ current = (yield* waitUntilReady(name, current.id)) ?? current;
646
+ }
647
+ // List/get omit `environment` after create. Keep the create
648
+ // payload as the secrets source for keepSecret below.
649
+ previous = toAttrs(createdSecrets, previous, { name, orgSlug });
650
+ }
651
+
652
+ if (current === undefined || current.id.length === 0) {
653
+ return yield* new BucketNotCreated({ name });
654
+ }
655
+
656
+ const status = current.status ?? undefined;
657
+ if (failedStatus(status)) {
658
+ return yield* new BucketProvisionFailed({
659
+ name,
660
+ status,
661
+ errorMessage: current.errorMessage ?? undefined,
662
+ });
663
+ }
664
+
665
+ const observedOptions = asRecord(current.options);
666
+ const desired = desiredOptions(props);
667
+ const internal = yield* createInternalTags(id);
668
+ const observedMeta = stringRecordOf(current.metadata);
669
+ const nextMeta = { ...observedMeta, ...internal };
670
+ const optionsChanged = !optionsEqual(observedOptions, desired);
671
+ const metaChanged = !deepEqual(observedMeta, nextMeta);
672
+ if (optionsChanged || metaChanged) {
673
+ const nextOptions = {
674
+ ...observedOptions,
675
+ ...desired,
676
+ };
677
+ const updated = yield* Effect.result(
678
+ addons.updateAddOn({
679
+ input: {
680
+ addOnId: current.id,
681
+ options: optionsChanged ? nextOptions : undefined,
682
+ metadata: metaChanged ? nextMeta : undefined,
683
+ },
684
+ }),
685
+ );
686
+ if (Result.isSuccess(updated)) {
687
+ current = {
688
+ ...current,
689
+ ...updated.success.addOn,
690
+ };
691
+ } else {
692
+ current = (yield* findById(current.id)) ?? current;
693
+ }
694
+ }
695
+
696
+ const latest = (yield* findById(current.id)) ?? current;
697
+ // GraphQL list/get omit `environment` after create. Keep credentials
698
+ // from the create payload (or last persisted attrs) via keepSecret.
699
+ const attrs = toAttrs(latest, toAttrs(current, previous, { name, orgSlug }), {
700
+ name,
701
+ orgSlug,
702
+ });
703
+ const observedPublic = asRecord(latest.options).public;
704
+ return {
705
+ ...attrs,
706
+ public:
707
+ typeof observedPublic === "boolean" ? observedPublic : (props.public ?? attrs.public),
708
+ domainName: websiteDomain(asRecord(latest.options)) ?? props.domainName ?? attrs.domainName,
709
+ accelerate:
710
+ typeof asRecord(latest.options).accelerate === "boolean"
711
+ ? (asRecord(latest.options).accelerate as boolean)
712
+ : (props.accelerate ?? attrs.accelerate),
713
+ };
714
+ }),
715
+
716
+ delete: Effect.fn(function* ({ output }) {
717
+ const addOnId = output.addOnId;
718
+ const name = output.name;
719
+ if (addOnId.length === 0 && name.length === 0) return;
720
+ // Always wait for the add-on to leave the list. A failed
721
+ // deleteAddOn plus a single list miss is not gone — Tigris
722
+ // list lags, and a bucket still attached to an App is a
723
+ // transient error. waitUntilGone retries delete and only
724
+ // succeeds once list (id and name) is empty.
725
+ yield* waitUntilGone(addOnId, name);
726
+ }),
727
+ });
728
+
729
+ class BucketSecretVersionMissing extends Data.TaggedError("Fly.BucketSecretVersionMissing")<{
730
+ appName: string;
731
+ }> {}
732
+
733
+ const bucketSecretVersion = (
734
+ appName: string,
735
+ response: machines.AppSecretsUpdateResp | machines.SetAppSecretResponse,
736
+ ) => {
737
+ const version = response.version ?? response.Version;
738
+ return version !== undefined && Number.isSafeInteger(version) && version >= 0
739
+ ? Effect.succeed(version)
740
+ : Effect.fail(new BucketSecretVersionMissing({ appName }));
741
+ };
742
+
743
+ const requireBucketSecrets = Effect.fn(function* (appName: string, values: Record<string, string>) {
744
+ const required = [
745
+ "BUCKET_NAME",
746
+ "AWS_ACCESS_KEY_ID",
747
+ "AWS_SECRET_ACCESS_KEY",
748
+ "AWS_ENDPOINT_URL_S3",
749
+ ];
750
+ if (required.some((key) => !values[key]?.trim())) {
751
+ return yield* new TigrisCredentialsMissing({
752
+ name: values.BUCKET_NAME || appName,
753
+ });
754
+ }
755
+ });
756
+
757
+ const putSecretValues = (appName: string, values: Record<string, string>) =>
758
+ Effect.gen(function* () {
759
+ yield* requireBucketSecrets(appName, values);
760
+ return yield* machines
761
+ .updateSecrets({
762
+ app_name: appName,
763
+ values,
764
+ })
765
+ .pipe(
766
+ Effect.flatMap((response) => bucketSecretVersion(appName, response)),
767
+ Effect.catchTag("NotFound", () =>
768
+ Effect.gen(function* () {
769
+ const versions: number[] = [];
770
+ for (const [secretName, value] of Object.entries(values)) {
771
+ const version = yield* machines
772
+ .createSecret({
773
+ app_name: appName,
774
+ secret_name: secretName,
775
+ value,
776
+ })
777
+ .pipe(
778
+ Effect.flatMap((response) => bucketSecretVersion(appName, response)),
779
+ Effect.catchTag("Conflict", () =>
780
+ machines
781
+ .updateSecrets({
782
+ app_name: appName,
783
+ values: { [secretName]: value },
784
+ })
785
+ .pipe(Effect.flatMap((response) => bucketSecretVersion(appName, response))),
786
+ ),
787
+ );
788
+ versions.push(version);
789
+ }
790
+ return Math.max(...versions);
791
+ }),
792
+ ),
793
+ );
794
+ });
795
+
796
+ const envValuesOf = (addOn: ObservedAddOn): Record<string, string> => {
797
+ const env = asRecord(addOn.environment);
798
+ const values: Record<string, string> = {};
799
+ for (const key of BUCKET_SECRET_NAMES) {
800
+ const value = envString(env, key);
801
+ if (value !== undefined) values[key] = value;
802
+ }
803
+ if (values.BUCKET_NAME === undefined && addOn.name != null) {
804
+ values.BUCKET_NAME = addOn.name;
805
+ }
806
+ if (values.AWS_ENDPOINT_URL === undefined && values.AWS_ENDPOINT_URL_S3 !== undefined) {
807
+ values.AWS_ENDPOINT_URL = values.AWS_ENDPOINT_URL_S3;
808
+ }
809
+ return values;
810
+ };
811
+
812
+ const findAttachedBucket = (input: { id?: string; name: string }) =>
813
+ Effect.gen(function* () {
814
+ const listed =
815
+ input.id !== undefined && input.id.length > 0
816
+ ? ((yield* findById(input.id)) ??
817
+ (input.name.length > 0 ? yield* findByName(input.name) : undefined))
818
+ : input.name.length > 0
819
+ ? yield* findByName(input.name)
820
+ : undefined;
821
+ if (listed === undefined) {
822
+ return yield* new BucketPending({
823
+ name: input.name || input.id || "",
824
+ status: "missing",
825
+ });
826
+ }
827
+ const detail = yield* addons
828
+ .addOn({
829
+ id: listed.id,
830
+ name: listed.name ?? input.name,
831
+ provider: TIGRIS,
832
+ })
833
+ .pipe(Effect.catchTag("FlyIoParseError", () => Effect.succeed(undefined)));
834
+ return detail ?? listed;
835
+ });
836
+
837
+ const secretsFromBoundEnv = (env: Record<string, string>): Record<string, string> => {
838
+ const values: Record<string, string> = {};
839
+ for (const key of BUCKET_SECRET_NAMES) {
840
+ const value = env[key];
841
+ if (value !== undefined && value.length > 0) values[key] = value;
842
+ }
843
+ if (values.AWS_ENDPOINT_URL === undefined && values.AWS_ENDPOINT_URL_S3 !== undefined) {
844
+ values.AWS_ENDPOINT_URL = values.AWS_ENDPOINT_URL_S3;
845
+ }
846
+ return values;
847
+ };
848
+
849
+ /**
850
+ * Write Tigris `AWS_*` / `BUCKET_NAME` secrets onto an App. Called from
851
+ * {@link Service} reconcile so the secrets exist before Machines boot.
852
+ *
853
+ * Looks up the add-on by id/name (retrying while Tigris is still
854
+ * provisioning) and also copies any already-evaluated `AWS_*` /
855
+ * `BUCKET_NAME` values from binding env — GraphQL `environment` is often
856
+ * empty after create. A missing add-on may use bound values only when the
857
+ * bucket name, credential pair, and S3 endpoint are complete. Partial values
858
+ * are never written. Region is optional, as in the Tigris bindings.
859
+ * Without an attachment, only an explicit `BUCKET_NAME` requests this mode;
860
+ * ordinary AWS region or credential settings do not imply a Bucket.
861
+ * Returns the highest accepted secret-version floor, or `undefined` when
862
+ * no Bucket was requested; this is not a vault snapshot.
863
+ */
864
+ export const attachBucketSecrets = Effect.fn(function* (
865
+ appName: string,
866
+ attached: readonly {
867
+ name: string;
868
+ id?: string;
869
+ /** Credentials from the bound Bucket's attributes. */
870
+ values?: Record<string, string>;
871
+ }[],
872
+ boundEnv: Record<string, string> = {},
873
+ ) {
874
+ if (appName.length === 0) return undefined;
875
+ if (attached.length === 0 && boundEnv.BUCKET_NAME === undefined) {
876
+ return undefined;
877
+ }
878
+ const fromEnv = secretsFromBoundEnv(boundEnv);
879
+ if (attached.length === 0) {
880
+ return yield* putSecretValues(appName, fromEnv);
881
+ }
882
+ const versions: number[] = [];
883
+ for (const item of attached) {
884
+ const name = item.name;
885
+ const id = item.id;
886
+ const fallbackValues: Record<string, string> = {
887
+ ...fromEnv,
888
+ ...item.values,
889
+ };
890
+ if (
891
+ fallbackValues.AWS_ENDPOINT_URL === undefined &&
892
+ fallbackValues.AWS_ENDPOINT_URL_S3 !== undefined
893
+ ) {
894
+ fallbackValues.AWS_ENDPOINT_URL = fallbackValues.AWS_ENDPOINT_URL_S3;
895
+ }
896
+ if (fallbackValues.BUCKET_NAME === undefined && name.length > 0) {
897
+ fallbackValues.BUCKET_NAME = name;
898
+ }
899
+ const row = yield* findAttachedBucket({ id, name }).pipe(
900
+ Effect.retry({
901
+ while: (error) => error._tag === "Fly.BucketPending",
902
+ times: 8,
903
+ schedule: backoff,
904
+ }),
905
+ Effect.catchTag("Fly.BucketPending", () =>
906
+ requireBucketSecrets(appName, fallbackValues).pipe(Effect.as(undefined)),
907
+ ),
908
+ );
909
+ const values = {
910
+ ...fallbackValues,
911
+ ...(row === undefined ? {} : envValuesOf(row)),
912
+ };
913
+ versions.push(yield* putSecretValues(appName, values));
914
+ }
915
+ return versions.length > 0 ? Math.max(...versions) : undefined;
916
+ });