@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
@@ -0,0 +1,708 @@
1
+ import * as machines from "@distilled.cloud/fly-io/machines";
2
+ import type { Machine } from "@distilled.cloud/fly-io/machines";
3
+ import * as Retry from "@distilled.cloud/fly-io/Retry";
4
+ import { deepEqual } from "alchemy/Diff";
5
+ import { sha256Object } from "alchemy/Util/sha256";
6
+ import * as Data from "effect/Data";
7
+ import * as Effect from "effect/Effect";
8
+ import * as Schedule from "effect/Schedule";
9
+ import {
10
+ applyImageSet,
11
+ encodeImageSet,
12
+ pinsFromConfig,
13
+ sameImageSet,
14
+ validObservedImageSet,
15
+ } from "./DeploymentImages.ts";
16
+ import { classifyDeploymentState, validProtocol2Generation } from "./DeploymentState.ts";
17
+ import { usingMachineLeases, type MachineLeases } from "./leases.ts";
18
+ import { canonicalContainers } from "./MachineContainers.ts";
19
+ import { alchemyMetadataKeys as keys } from "./Metadata.ts";
20
+ import { regionOfReplica } from "./Region.ts";
21
+ import {
22
+ autostopMode,
23
+ checksPassing,
24
+ deleteMachine,
25
+ ensureStarted,
26
+ getMachineById,
27
+ groupGenerations,
28
+ hasPublishedService,
29
+ listMachinesByApp,
30
+ leaseSnapshot,
31
+ ownedReplicas,
32
+ ReplicaNotCreated,
33
+ replicaIndexOf,
34
+ retireMachines,
35
+ sameChecks,
36
+ sameServices,
37
+ sameStopConfig,
38
+ toReplica,
39
+ toReplicaSet,
40
+ waitHealthy,
41
+ type ReconcileReplicasInput,
42
+ } from "./replicas.ts";
43
+
44
+ const metadataOf = (machine: Machine) =>
45
+ Object.fromEntries(
46
+ Object.entries(machine.config?.metadata ?? {}).flatMap(([key, value]) =>
47
+ value === undefined ? [] : [[key, value]],
48
+ ),
49
+ );
50
+
51
+ const setMetadata = Effect.fn(function* (
52
+ appName: string,
53
+ machine: Machine,
54
+ metadata: Record<string, string>,
55
+ leases: MachineLeases,
56
+ ) {
57
+ yield* leases.checkTarget(machine.id!);
58
+ // Metadata is not nonce-fenced by Fly; it is recovery evidence, not a lock.
59
+ yield* leases.mutate(
60
+ machine.id!,
61
+ () =>
62
+ machines
63
+ .patchMachineMetadata({ app_name: appName, machine_id: machine.id!, metadata })
64
+ .pipe(Effect.timeout("30 seconds")),
65
+ { idempotent: true },
66
+ );
67
+ yield* Effect.sync(() => {
68
+ machine.config = { ...machine.config, metadata };
69
+ });
70
+ });
71
+
72
+ const phase = Effect.fn(function* (
73
+ appName: string,
74
+ machine: Machine,
75
+ value: string,
76
+ leases: MachineLeases,
77
+ ) {
78
+ if (machine.config?.metadata?.[keys.phase] !== value) {
79
+ yield* setMetadata(appName, machine, { ...metadataOf(machine), [keys.phase]: value }, leases);
80
+ }
81
+ });
82
+
83
+ export const setRouting = (
84
+ appName: string,
85
+ machineId: string,
86
+ cordoned: boolean,
87
+ existingLeases?: MachineLeases,
88
+ ) =>
89
+ usingMachineLeases(appName, existingLeases, (leases) =>
90
+ Effect.gen(function* () {
91
+ yield* leases.acquire([machineId]);
92
+ yield* leases.mutate(
93
+ machineId,
94
+ (lease_nonce) =>
95
+ Effect.gen(function* () {
96
+ const request = { app_name: appName, machine_id: machineId, lease_nonce };
97
+ if (cordoned) yield* machines.cordonMachine(request);
98
+ else yield* machines.uncordonMachine(request);
99
+ }).pipe(Effect.timeout("30 seconds")),
100
+ { idempotent: true },
101
+ );
102
+ yield* getMachineById(appName, machineId).pipe(
103
+ Effect.filterOrFail(
104
+ (machine) => machine !== undefined && machine.cordoned === cordoned,
105
+ () => new ReplicaNotCreated({ appName, name: machineId }),
106
+ ),
107
+ Effect.retry({
108
+ times: 8,
109
+ schedule: Schedule.spaced("500 millis"),
110
+ while: (error) => error._tag === "Fly.ReplicaNotCreated",
111
+ }),
112
+ );
113
+ }),
114
+ );
115
+
116
+ const pinnedImage = (machine: Machine) => {
117
+ const image = machine.image_ref;
118
+ if (!image?.digest || !image.repository) return undefined;
119
+ return `${image.registry ? `${image.registry}/` : ""}${image.repository}@${image.digest}`;
120
+ };
121
+
122
+ export class DeploymentRecoveryAmbiguous extends Data.TaggedError(
123
+ "Fly.DeploymentRecoveryAmbiguous",
124
+ )<{ appName: string; message: string }> {}
125
+
126
+ export const readinessRoles = (
127
+ config: machines.FlyMachineConfig,
128
+ count: number,
129
+ predecessors: Machine[],
130
+ ): Array<"run" | "idle"> => {
131
+ const services = config.services ?? [];
132
+ if (!services.length || services.some((service) => autostopMode(service.autostop) === "off")) {
133
+ return Array.from({ length: count }, () => "run");
134
+ }
135
+ const roles: Array<"run" | "idle"> = Array.from({ length: count }, (_, index) =>
136
+ predecessors.some((machine) => replicaIndexOf(machine) === index && machine.state === "started")
137
+ ? "run"
138
+ : "idle",
139
+ );
140
+ const floor = Math.min(
141
+ count,
142
+ Math.max(1, ...services.map((service) => service.min_machines_running ?? 0)),
143
+ );
144
+ for (let index = 0; roles.filter((role) => role === "run").length < floor; index++)
145
+ roles[index] = "run";
146
+ return roles;
147
+ };
148
+
149
+ const idle = (machine: Machine) =>
150
+ machine.state === "stopped" || machine.state === "suspended" || machine.state === "created";
151
+
152
+ /** Cloud metadata records preparation and promotion; replica zero commits a complete set. */
153
+ export const reconcileBlueGreen = Effect.fn(function* (
154
+ input: ReconcileReplicasInput,
155
+ ownership: Record<string, string>,
156
+ metadata: Record<string, string>,
157
+ leases: MachineLeases,
158
+ ) {
159
+ const config = input.buildConfig({ index: 0, mounts: [], metadata });
160
+ const containerPins = config.containers === undefined ? undefined : pinsFromConfig(config);
161
+ const containerMode = config.containers !== undefined;
162
+ const ambiguous = (message: string) =>
163
+ new DeploymentRecoveryAmbiguous({ appName: input.appName, message });
164
+ if (containerMode && containerPins === undefined)
165
+ return yield* ambiguous("Blue/green requires a complete immutable container image set.");
166
+ const workload = yield* sha256Object({
167
+ config: containerMode
168
+ ? { ...config, containers: canonicalContainers(config.containers) }
169
+ : config,
170
+ count: input.count,
171
+ minSecretsVersion: input.minSecretsVersion,
172
+ // A single region hashes as before, so existing generations stay current.
173
+ region: input.regions.length === 1 ? input.regions[0] : [...input.regions],
174
+ });
175
+ const observe = listMachinesByApp(input.appName).pipe(
176
+ Effect.flatMap((listed) => {
177
+ const owned = ownedReplicas(listed, {
178
+ ...input,
179
+ metadata: ownership,
180
+ machineIds: input.outputMachineIds,
181
+ });
182
+ const changed = listed.find(
183
+ (machine) =>
184
+ machine.id && input.outputMachineIds?.includes(machine.id) && !owned.includes(machine),
185
+ );
186
+ return changed
187
+ ? Effect.fail(
188
+ ambiguous(`Cached Machine ${changed.id} no longer has the expected ownership.`),
189
+ )
190
+ : Effect.succeed(owned);
191
+ }),
192
+ );
193
+ const snapshot = yield* observe;
194
+ const owned = yield* leaseSnapshot(input.appName, snapshot, leases);
195
+ // A vanished snapshot member can have a successor outside this inventory.
196
+ if (snapshot.some((machine) => !owned.some((current) => current.id === machine.id))) {
197
+ return yield* ambiguous(
198
+ "Owned Machine membership changed while acquiring leases; retry with a fresh deployment snapshot.",
199
+ );
200
+ }
201
+ for (const machine of owned) {
202
+ const state = classifyDeploymentState(machine);
203
+ if (state.protocol === "invalid")
204
+ return yield* ambiguous(`Machine ${machine.id}: ${state.reason}`);
205
+ }
206
+
207
+ const idleAllowed =
208
+ (config.services?.length ?? 0) > 0 &&
209
+ config.services!.every((service) => autostopMode(service.autostop) !== "off");
210
+ const preparationServices = config.services?.map((service) => ({ ...service, autostop: "off" }));
211
+ const mismatchOf = (machine: Machine): string | undefined => {
212
+ const observed = metadataOf(machine);
213
+ if (containerMode) {
214
+ if (
215
+ observed[keys.protocol] !== "2" ||
216
+ !validObservedImageSet(machine) ||
217
+ !sameImageSet(pinsFromConfig(machine.config), containerPins)
218
+ )
219
+ return "container image set";
220
+ } else {
221
+ const pinned = observed[keys.image];
222
+ if (pinned === undefined && observed[keys.phase] !== "candidate") return "metadata.image";
223
+ if (!pinnedImage(machine) || (pinned !== undefined && pinned !== pinnedImage(machine)))
224
+ return "image_ref";
225
+ }
226
+ const secretsVersion = Number(observed[keys.secretsVersion] ?? -1);
227
+ if (
228
+ input.minSecretsVersion !== undefined &&
229
+ (!Number.isSafeInteger(secretsVersion) || secretsVersion < input.minSecretsVersion)
230
+ )
231
+ return "metadata.secretsVersion";
232
+ const temporary =
233
+ observed[keys.role] === "run" &&
234
+ observed[keys.restored] === "false" &&
235
+ sameServices(machine.config?.services, preparationServices);
236
+ if (observed[keys.workload] !== workload) return "metadata.workload";
237
+ if (
238
+ input.configDrifted(
239
+ {
240
+ ...machine,
241
+ config: {
242
+ ...machine.config,
243
+ image: config.image,
244
+ services: temporary ? config.services : machine.config?.services,
245
+ },
246
+ },
247
+ {
248
+ mounts: [],
249
+ metadata: {
250
+ ...Object.fromEntries(
251
+ Object.entries(observed).filter(([key]) => key.startsWith("alchemy.")),
252
+ ),
253
+ ...metadata,
254
+ },
255
+ },
256
+ )
257
+ )
258
+ return "config";
259
+ if (!sameChecks(machine.config?.checks, config.checks)) return "config.checks";
260
+ if (!sameStopConfig(machine.config?.stop_config, config.stop_config))
261
+ return "config.stop_config";
262
+ return undefined;
263
+ };
264
+ const matches = (machine: Machine) => mismatchOf(machine) === undefined;
265
+ const groups = groupGenerations(owned);
266
+ const sequences = new Set<string>();
267
+ for (const [generation, group] of groups) {
268
+ if (generation === undefined) continue;
269
+ const sequence = group[0]?.config?.metadata?.[keys.sequence];
270
+ if (
271
+ !sequence ||
272
+ !Number.isSafeInteger(Number(sequence)) ||
273
+ Number(sequence) < 1 ||
274
+ sequences.has(sequence) ||
275
+ group.some((machine) => machine.config?.metadata?.[keys.sequence] !== sequence) ||
276
+ (group.some((machine) => machine.config?.metadata?.[keys.protocol] === "2") &&
277
+ !validProtocol2Generation(group))
278
+ ) {
279
+ return yield* ambiguous(
280
+ "Owned generations have ambiguous sequence/lineage metadata; preserving all capacity.",
281
+ );
282
+ }
283
+ sequences.add(sequence);
284
+ }
285
+ const reusable = [...groups.entries()]
286
+ .filter(([generation, group]) => generation !== undefined && group.every(matches))
287
+ .sort(
288
+ ([, a], [, b]) =>
289
+ Number(b[0]?.config?.metadata?.[keys.sequence] ?? 0) -
290
+ Number(a[0]?.config?.metadata?.[keys.sequence] ?? 0),
291
+ )[0];
292
+ const generation =
293
+ reusable?.[0] ??
294
+ (yield* sha256Object({
295
+ workload,
296
+ predecessors: owned.map((machine) => machine.id).sort(),
297
+ })).slice(0, 20);
298
+ const desired = reusable?.[1] ?? [];
299
+ if (
300
+ new Set(desired.map(replicaIndexOf)).size !== desired.length ||
301
+ desired.some((machine) => replicaIndexOf(machine) >= input.count)
302
+ ) {
303
+ return yield* ambiguous(
304
+ "The recovered generation has duplicate or out-of-range replica indices.",
305
+ );
306
+ }
307
+ const sequence =
308
+ desired[0]?.config?.metadata?.[keys.sequence] ??
309
+ String(
310
+ 1 +
311
+ Math.max(
312
+ 0,
313
+ ...owned.map((machine) => Number(machine.config?.metadata?.[keys.sequence] ?? 0)),
314
+ ),
315
+ );
316
+ const predecessors = owned.filter(
317
+ (machine) => machine.config?.metadata?.[keys.generation] !== generation,
318
+ );
319
+ const recordedRoles = desired[0]?.config?.metadata?.[keys.roles];
320
+ const roles = recordedRoles?.split(",") ?? readinessRoles(config, input.count, predecessors);
321
+ if (
322
+ roles.length !== input.count ||
323
+ roles.some((role) => role !== "run" && role !== "idle") ||
324
+ !roles.includes("run") ||
325
+ desired.some(
326
+ (machine) =>
327
+ machine.config?.metadata?.[keys.roles] !== recordedRoles ||
328
+ ((machine.config?.metadata?.[keys.protocol] === "1" ||
329
+ machine.config?.metadata?.[keys.protocol] === "2") &&
330
+ machine.config.metadata[keys.role] !== roles[replicaIndexOf(machine)]),
331
+ )
332
+ ) {
333
+ return yield* ambiguous("The recovered generation has inconsistent readiness roles.");
334
+ }
335
+ const complete =
336
+ desired.length === input.count &&
337
+ desired.every(
338
+ (machine) =>
339
+ machine.config?.metadata?.[keys.phase] === "active" &&
340
+ machine.config.metadata[keys.restored] === "true" &&
341
+ (roles[replicaIndexOf(machine)] === "idle" ||
342
+ (machine.instance_id !== undefined &&
343
+ machine.config.metadata[keys.checkedInstance] === machine.instance_id)) &&
344
+ machine.cordoned === false,
345
+ );
346
+ if (
347
+ complete &&
348
+ !predecessors.length &&
349
+ desired.every((machine) => machine.state === "started" || (idleAllowed && idle(machine)))
350
+ ) {
351
+ return toReplicaSet(
352
+ [...desired]
353
+ .sort((a, b) => replicaIndexOf(a) - replicaIndexOf(b))
354
+ .map((machine) => toReplica(machine, new Map())),
355
+ input.appName,
356
+ input.baseName,
357
+ config.services,
358
+ );
359
+ }
360
+ const candidates: Machine[] = [];
361
+ const snapshotIds = new Set(owned.map((machine) => machine.id));
362
+ let image = desired[0] ? pinnedImage(desired[0]) : undefined;
363
+ const order = Array.from({ length: input.count }, (_, index) => index).sort(
364
+ (a, b) => Number(roles[b] === "run") - Number(roles[a] === "run") || a - b,
365
+ );
366
+ // Creation-time predecessor IDs are diagnostic lineage, not deletion authority.
367
+ const predecessorIds = predecessors
368
+ .flatMap((machine) => (machine.id ? [machine.id] : []))
369
+ .sort()
370
+ .join(",");
371
+ yield* Effect.gen(function* () {
372
+ for (const index of order) {
373
+ const suffix = `-${generation}-${index}`;
374
+ const name = `${input.baseName.slice(0, 30 - suffix.length).replace(/-+$/g, "")}${suffix}`;
375
+ let current = desired.find((machine) => replicaIndexOf(machine) === index);
376
+ if (current === undefined) {
377
+ const run = roles[index] === "run";
378
+ const candidateConfig = input.buildConfig({
379
+ index,
380
+ mounts: [],
381
+ metadata: {
382
+ ...metadata,
383
+ [keys.replica]: String(index),
384
+ [keys.generation]: generation,
385
+ [keys.workload]: workload,
386
+ [keys.phase]: "candidate",
387
+ [keys.sequence]: sequence,
388
+ [keys.count]: String(input.count),
389
+ [keys.protocol]: containerMode ? "2" : "1",
390
+ [keys.roles]: roles.join(","),
391
+ [keys.role]: roles[index]!,
392
+ [keys.predecessors]: predecessorIds,
393
+ [keys.restored]: String(!run || sameServices(config.services, preparationServices)),
394
+ ...(input.minSecretsVersion === undefined
395
+ ? {}
396
+ : { [keys.secretsVersion]: String(input.minSecretsVersion) }),
397
+ ...(containerPins
398
+ ? { [keys.containerImageSet]: encodeImageSet(containerPins)! }
399
+ : image
400
+ ? { [keys.image]: image }
401
+ : {}),
402
+ },
403
+ });
404
+ const pinnedConfig = containerPins
405
+ ? applyImageSet(candidateConfig, containerPins)
406
+ : candidateConfig;
407
+ if (pinnedConfig === undefined) return yield* ambiguous("Incomplete candidate image set.");
408
+ const readback = observe.pipe(
409
+ Effect.map((listed) =>
410
+ listed.find(
411
+ (machine) =>
412
+ machine.name === name &&
413
+ machine.config?.metadata?.[keys.generation] === generation &&
414
+ replicaIndexOf(machine) === index &&
415
+ matches(machine),
416
+ ),
417
+ ),
418
+ Effect.filterOrFail(
419
+ (machine) => machine !== undefined,
420
+ () => new ReplicaNotCreated({ appName: input.appName, name }),
421
+ ),
422
+ Effect.retry({
423
+ times: 8,
424
+ schedule: Schedule.spaced("500 millis"),
425
+ while: (error) => error._tag === "Fly.ReplicaNotCreated",
426
+ }),
427
+ );
428
+ current = yield* machines
429
+ .createMachine({
430
+ app_name: input.appName,
431
+ name,
432
+ region: regionOfReplica(input.regions, index),
433
+ config: {
434
+ ...pinnedConfig,
435
+ image: containerPins ? undefined : (image ?? config.image),
436
+ services: run ? preparationServices : config.services,
437
+ },
438
+ skip_launch: !run,
439
+ skip_service_registration: true,
440
+ min_secrets_version: input.minSecretsVersion,
441
+ })
442
+ .pipe(
443
+ Retry.none,
444
+ Effect.timeout("30 seconds"),
445
+ Effect.catchTag(["Conflict", "GatewayTimeout", "TimeoutError"], () => readback),
446
+ Effect.catchReason("HttpClientError", "TransportError", () => readback),
447
+ );
448
+ }
449
+ if (!current?.id) return yield* new ReplicaNotCreated({ appName: input.appName, name });
450
+ const leased = (yield* leaseSnapshot(input.appName, [current], leases))[0];
451
+ if (!leased?.id)
452
+ return yield* ambiguous(
453
+ `Candidate ${current.id} disappeared before its lease was acquired.`,
454
+ );
455
+ const mismatch = mismatchOf(leased);
456
+ if (mismatch !== undefined)
457
+ return yield* ambiguous(
458
+ `Candidate ${current.id} changed before its lease was acquired. Mismatch: ${mismatch}.`,
459
+ );
460
+ current = leased;
461
+ snapshotIds.add(current.id);
462
+ if (containerPins) {
463
+ if (
464
+ !validObservedImageSet(current) ||
465
+ !sameImageSet(pinsFromConfig(current.config), containerPins)
466
+ )
467
+ return yield* ambiguous(`Container image pin mismatch on ${current.id}.`);
468
+ } else {
469
+ const resolvedImage = pinnedImage(current);
470
+ if (!resolvedImage || (image !== undefined && image !== resolvedImage))
471
+ return yield* ambiguous(`Image pin mismatch on ${current.id}.`);
472
+ image = resolvedImage;
473
+ if (current.config?.metadata?.[keys.image] !== image)
474
+ yield* setMetadata(
475
+ input.appName,
476
+ current,
477
+ { ...metadataOf(current), [keys.image]: image },
478
+ leases,
479
+ );
480
+ }
481
+ const checked =
482
+ current.config?.metadata?.[keys.checkedInstance] === current.instance_id &&
483
+ current.instance_id !== undefined;
484
+ if (roles[index] === "run" && !(idleAllowed && checked && idle(current))) {
485
+ current = yield* ensureStarted(
486
+ input.appName,
487
+ current,
488
+ false,
489
+ input.policy.healthTimeoutMs,
490
+ current.config,
491
+ leases,
492
+ );
493
+ } else if (!idle(current)) {
494
+ current = yield* waitHealthy(
495
+ input.appName,
496
+ current,
497
+ input.policy.healthTimeoutMs,
498
+ current.config,
499
+ );
500
+ }
501
+ candidates[index] = current;
502
+ }
503
+ }).pipe(
504
+ Effect.catch((error) =>
505
+ Effect.gen(function* () {
506
+ const found = (yield* observe).filter(
507
+ (machine) =>
508
+ snapshotIds.has(machine.id) &&
509
+ machine.config?.metadata?.[keys.generation] === generation,
510
+ );
511
+ // A possibly promoted candidate is capacity, not rollback garbage.
512
+ if (
513
+ found.every(
514
+ (machine) =>
515
+ (!containerMode || matches(machine)) &&
516
+ machine.config?.metadata?.[keys.phase] === "candidate" &&
517
+ machine.cordoned === true,
518
+ )
519
+ ) {
520
+ yield* Effect.forEach(
521
+ found,
522
+ (machine) =>
523
+ deleteMachine(input.appName, machine.id!, leases).pipe(
524
+ Effect.catch((cleanup) =>
525
+ Effect.logWarning("Fly candidate cleanup remains pending", {
526
+ appName: input.appName,
527
+ machineId: machine.id,
528
+ error: cleanup._tag,
529
+ }),
530
+ ),
531
+ ),
532
+ { concurrency: 4 },
533
+ );
534
+ }
535
+ return yield* error;
536
+ }),
537
+ ),
538
+ );
539
+
540
+ const needsPromotion = candidates.some(
541
+ (machine) => machine.cordoned !== false || machine.config?.metadata?.[keys.phase] !== "active",
542
+ );
543
+ if (needsPromotion) {
544
+ for (const machine of candidates) yield* phase(input.appName, machine, "promoting", leases);
545
+ // Promotion metadata resets reports; validate the whole set before routing any member.
546
+ for (const [index, machine] of candidates.entries()) {
547
+ const current = yield* getMachineById(input.appName, machine.id!);
548
+ if (!current || !matches(current))
549
+ return yield* ambiguous(`Candidate ${machine.id} changed before promotion.`);
550
+ if (current.state === "started") {
551
+ candidates[index] = yield* waitHealthy(
552
+ input.appName,
553
+ current,
554
+ input.policy.healthTimeoutMs,
555
+ current.config,
556
+ );
557
+ } else if (
558
+ !idleAllowed ||
559
+ !idle(current) ||
560
+ (roles[index] === "run" &&
561
+ (current.instance_id === undefined ||
562
+ current.config?.metadata?.[keys.checkedInstance] !== current.instance_id))
563
+ ) {
564
+ return yield* ambiguous(`Candidate ${machine.id} has no readiness proof before promotion.`);
565
+ } else candidates[index] = current;
566
+ }
567
+ for (const machine of candidates)
568
+ if (machine.cordoned !== false) yield* setRouting(input.appName, machine.id!, false, leases);
569
+ if (hasPublishedService(config.services)) yield* Effect.sleep("10 seconds");
570
+ }
571
+ for (const [index, machine] of candidates.entries()) {
572
+ let current = machine;
573
+ if (current.config?.metadata?.[keys.restored] === "false") {
574
+ // Restoring services creates a new instance; its predecessor's checks cannot prove readiness.
575
+ const machineId = current.id!;
576
+ const currentVersion = current.instance_id;
577
+ const restoreConfig = input.buildConfig({
578
+ index,
579
+ mounts: [],
580
+ metadata: { ...metadataOf(current), [keys.restored]: "true" },
581
+ });
582
+ const restored = containerPins
583
+ ? applyImageSet(restoreConfig, containerPins)
584
+ : { ...restoreConfig, image };
585
+ if (restored === undefined)
586
+ return yield* ambiguous("Incomplete image set during service restoration.");
587
+ current = yield* leases.mutate(machineId, (lease_nonce) =>
588
+ machines
589
+ .updateMachine({
590
+ app_name: input.appName,
591
+ machine_id: machineId,
592
+ lease_nonce,
593
+ current_version: currentVersion,
594
+ config: restored,
595
+ min_secrets_version: input.minSecretsVersion,
596
+ })
597
+ .pipe(Effect.timeout("30 seconds")),
598
+ );
599
+ current = yield* ensureStarted(
600
+ input.appName,
601
+ current,
602
+ false,
603
+ input.policy.healthTimeoutMs,
604
+ config,
605
+ leases,
606
+ );
607
+ } else {
608
+ current = (yield* getMachineById(input.appName, current.id!)) ?? current;
609
+ if (current.instance_id !== machine.instance_id) {
610
+ current = yield* ensureStarted(
611
+ input.appName,
612
+ current,
613
+ false,
614
+ input.policy.healthTimeoutMs,
615
+ config,
616
+ leases,
617
+ );
618
+ }
619
+ if (
620
+ current.state !== "started" &&
621
+ roles[index] === "run" &&
622
+ current.config?.metadata?.[keys.checkedInstance] !== current.instance_id
623
+ ) {
624
+ current = yield* ensureStarted(
625
+ input.appName,
626
+ current,
627
+ false,
628
+ input.policy.healthTimeoutMs,
629
+ config,
630
+ leases,
631
+ );
632
+ }
633
+ }
634
+ candidates[index] = current;
635
+ }
636
+ // Reset reports while still pending; an interrupted validation is not a commit.
637
+ for (const machine of candidates) yield* phase(input.appName, machine, "validating", leases);
638
+ for (const [index, machine] of candidates.entries()) {
639
+ const current = yield* getMachineById(input.appName, machine.id!);
640
+ if (!current || !matches(current) || current.config?.metadata?.[keys.restored] !== "true")
641
+ return yield* ambiguous(`Candidate ${machine.id} changed before commitment.`);
642
+ if (current.state === "started")
643
+ candidates[index] = yield* waitHealthy(
644
+ input.appName,
645
+ current,
646
+ input.policy.healthTimeoutMs,
647
+ config,
648
+ );
649
+ else if (
650
+ !idleAllowed ||
651
+ !idle(current) ||
652
+ (roles[index] === "run" &&
653
+ (current.instance_id === undefined ||
654
+ (current.config?.metadata?.[keys.checkedInstance] !== current.instance_id &&
655
+ !(machine.instance_id === current.instance_id && checksPassing(machine, config)))))
656
+ ) {
657
+ return yield* ambiguous(
658
+ `Candidate ${machine.id} has no readiness proof for its current instance.`,
659
+ );
660
+ } else candidates[index] = current;
661
+ }
662
+ // All final checks precede the commit stamps, with replica zero last.
663
+ for (const machine of [...candidates].reverse()) {
664
+ const committed = {
665
+ ...metadataOf(machine),
666
+ [keys.phase]: "active",
667
+ ...(machine.state === "started" || roles[replicaIndexOf(machine)] === "run"
668
+ ? { [keys.checkedInstance]: machine.instance_id! }
669
+ : {}),
670
+ };
671
+ if (!deepEqual(metadataOf(machine), committed))
672
+ yield* setMetadata(input.appName, machine, committed, leases);
673
+ }
674
+ // Legacy ownership is required; predecessor phase stamps are only advisory.
675
+ for (const machine of predecessors) {
676
+ if (machine.config?.metadata?.[keys.protocol] === "2") {
677
+ const observed = yield* getMachineById(input.appName, machine.id!);
678
+ if (
679
+ !observed ||
680
+ observed.config?.metadata?.[keys.protocol] !== "2" ||
681
+ !validObservedImageSet(observed) ||
682
+ !sameImageSet(pinsFromConfig(observed.config), pinsFromConfig(machine.config))
683
+ )
684
+ return yield* ambiguous(
685
+ `Predecessor ${machine.id} image identity changed before retirement.`,
686
+ );
687
+ }
688
+ if (machine.config?.metadata?.[keys.instance] === undefined)
689
+ yield* setMetadata(input.appName, machine, { ...metadataOf(machine), ...metadata }, leases);
690
+ if (machine.host_status !== "unreachable")
691
+ yield* phase(input.appName, machine, "retiring", leases).pipe(
692
+ Effect.catch((error) =>
693
+ Effect.logWarning("Fly predecessor phase metadata was not updated", {
694
+ appName: input.appName,
695
+ machineId: machine.id,
696
+ error: error._tag,
697
+ }),
698
+ ),
699
+ );
700
+ }
701
+ yield* retireMachines(input.appName, predecessors, true, leases);
702
+ return toReplicaSet(
703
+ candidates.map((machine) => toReplica(machine, new Map())),
704
+ input.appName,
705
+ input.baseName,
706
+ config.services,
707
+ );
708
+ });