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

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 +338 -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 +55 -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 +20 -0
  176. package/lib/PostgresMigrations.d.ts.map +1 -0
  177. package/lib/PostgresMigrations.js +58 -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 +611 -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 +11 -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 +1017 -0
  240. package/lib/Service.d.ts.map +1 -0
  241. package/lib/Service.js +1430 -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 +471 -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 +89 -0
  280. package/lib/Website/Astro.d.ts.map +1 -0
  281. package/lib/Website/Astro.js +54 -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 +212 -0
  288. package/lib/Website/FrameworkSite.d.ts.map +1 -0
  289. package/lib/Website/FrameworkSite.js +205 -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 +162 -0
  312. package/lib/Website/StaticSite.d.ts.map +1 -0
  313. package/lib/Website/StaticSite.js +180 -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 +112 -0
  328. package/lib/Website/Vite.d.ts.map +1 -0
  329. package/lib/Website/Vite.js +100 -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 +460 -0
  370. package/lib/bluegreen.js.map +1 -0
  371. package/lib/hosted.d.ts +171 -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 +158 -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 +514 -0
  401. package/src/AuthProvider.ts +68 -0
  402. package/src/BindService.ts +303 -0
  403. package/src/Bootstrap.ts +66 -0
  404. package/src/Bucket.ts +918 -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 +75 -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 +1270 -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 +93 -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 +823 -0
  452. package/src/RedisBinding.ts +64 -0
  453. package/src/RedisHttp.ts +14 -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 +1968 -0
  460. package/src/Sign.ts +46 -0
  461. package/src/SignHttp.ts +44 -0
  462. package/src/Sprite.ts +673 -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 +292 -0
  469. package/src/Website/Astro.ts +92 -0
  470. package/src/Website/Foldkit.ts +54 -0
  471. package/src/Website/FrameworkSite.ts +449 -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 +295 -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 +121 -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 +711 -0
  492. package/src/globals.d.ts +2 -0
  493. package/src/hosted.ts +667 -0
  494. package/src/index.ts +64 -0
  495. package/src/internal/RemoteBuilder.ts +242 -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,711 @@
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, resourceName: 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
297
+ .map((machine) => machine.id)
298
+ .sort((a, b) => ((a ?? "") < (b ?? "") ? -1 : (a ?? "") > (b ?? "") ? 1 : 0)),
299
+ })).slice(0, 20);
300
+ const desired = reusable?.[1] ?? [];
301
+ if (
302
+ new Set(desired.map(replicaIndexOf)).size !== desired.length ||
303
+ desired.some((machine) => replicaIndexOf(machine) >= input.count)
304
+ ) {
305
+ return yield* ambiguous(
306
+ "The recovered generation has duplicate or out-of-range replica indices.",
307
+ );
308
+ }
309
+ const sequence =
310
+ desired[0]?.config?.metadata?.[keys.sequence] ??
311
+ String(
312
+ 1 +
313
+ Math.max(
314
+ 0,
315
+ ...owned.map((machine) => Number(machine.config?.metadata?.[keys.sequence] ?? 0)),
316
+ ),
317
+ );
318
+ const predecessors = owned.filter(
319
+ (machine) => machine.config?.metadata?.[keys.generation] !== generation,
320
+ );
321
+ const recordedRoles = desired[0]?.config?.metadata?.[keys.roles];
322
+ const roles = recordedRoles?.split(",") ?? readinessRoles(config, input.count, predecessors);
323
+ if (
324
+ roles.length !== input.count ||
325
+ roles.some((role) => role !== "run" && role !== "idle") ||
326
+ !roles.includes("run") ||
327
+ desired.some(
328
+ (machine) =>
329
+ machine.config?.metadata?.[keys.roles] !== recordedRoles ||
330
+ ((machine.config?.metadata?.[keys.protocol] === "1" ||
331
+ machine.config?.metadata?.[keys.protocol] === "2") &&
332
+ machine.config.metadata[keys.role] !== roles[replicaIndexOf(machine)]),
333
+ )
334
+ ) {
335
+ return yield* ambiguous("The recovered generation has inconsistent readiness roles.");
336
+ }
337
+ const complete =
338
+ desired.length === input.count &&
339
+ desired.every(
340
+ (machine) =>
341
+ machine.config?.metadata?.[keys.phase] === "active" &&
342
+ machine.config.metadata[keys.restored] === "true" &&
343
+ (roles[replicaIndexOf(machine)] === "idle" ||
344
+ (machine.instance_id !== undefined &&
345
+ machine.config.metadata[keys.checkedInstance] === machine.instance_id)) &&
346
+ machine.cordoned === false,
347
+ );
348
+ if (
349
+ complete &&
350
+ !predecessors.length &&
351
+ desired.every((machine) => machine.state === "started" || (idleAllowed && idle(machine)))
352
+ ) {
353
+ return toReplicaSet(
354
+ [...desired]
355
+ .sort((a, b) => replicaIndexOf(a) - replicaIndexOf(b))
356
+ .map((machine) => toReplica(machine, new Map())),
357
+ input.appName,
358
+ input.baseName,
359
+ config.services,
360
+ );
361
+ }
362
+ const candidates: Machine[] = [];
363
+ const snapshotIds = new Set(owned.map((machine) => machine.id));
364
+ let image = desired[0] ? pinnedImage(desired[0]) : undefined;
365
+ const order = Array.from({ length: input.count }, (_, index) => index).sort(
366
+ (a, b) => Number(roles[b] === "run") - Number(roles[a] === "run") || a - b,
367
+ );
368
+ // Creation-time predecessor IDs are diagnostic lineage, not deletion authority.
369
+ const predecessorIds = predecessors
370
+ .flatMap((machine) => (machine.id ? [machine.id] : []))
371
+ .sort()
372
+ .join(",");
373
+ yield* Effect.gen(function* () {
374
+ for (const index of order) {
375
+ const suffix = `-${generation}-${index}`;
376
+ const name = `${input.baseName.slice(0, 30 - suffix.length).replace(/-+$/g, "")}${suffix}`;
377
+ let current = desired.find((machine) => replicaIndexOf(machine) === index);
378
+ if (current === undefined) {
379
+ const run = roles[index] === "run";
380
+ const candidateConfig = input.buildConfig({
381
+ index,
382
+ mounts: [],
383
+ metadata: {
384
+ ...metadata,
385
+ [keys.replica]: String(index),
386
+ [keys.generation]: generation,
387
+ [keys.workload]: workload,
388
+ [keys.phase]: "candidate",
389
+ [keys.sequence]: sequence,
390
+ [keys.count]: String(input.count),
391
+ [keys.protocol]: containerMode ? "2" : "1",
392
+ [keys.roles]: roles.join(","),
393
+ [keys.role]: roles[index]!,
394
+ [keys.predecessors]: predecessorIds,
395
+ [keys.restored]: String(!run || sameServices(config.services, preparationServices)),
396
+ ...(input.minSecretsVersion === undefined
397
+ ? {}
398
+ : { [keys.secretsVersion]: String(input.minSecretsVersion) }),
399
+ ...(containerPins
400
+ ? { [keys.containerImageSet]: encodeImageSet(containerPins)! }
401
+ : image
402
+ ? { [keys.image]: image }
403
+ : {}),
404
+ },
405
+ });
406
+ const pinnedConfig = containerPins
407
+ ? applyImageSet(candidateConfig, containerPins)
408
+ : candidateConfig;
409
+ if (pinnedConfig === undefined) return yield* ambiguous("Incomplete candidate image set.");
410
+ const readback = observe.pipe(
411
+ Effect.map((listed) =>
412
+ listed.find(
413
+ (machine) =>
414
+ machine.name === name &&
415
+ machine.config?.metadata?.[keys.generation] === generation &&
416
+ replicaIndexOf(machine) === index &&
417
+ matches(machine),
418
+ ),
419
+ ),
420
+ Effect.filterOrFail(
421
+ (machine) => machine !== undefined,
422
+ () => new ReplicaNotCreated({ appName: input.appName, resourceName: name }),
423
+ ),
424
+ Effect.retry({
425
+ times: 8,
426
+ schedule: Schedule.spaced("500 millis"),
427
+ while: (error) => error._tag === "Fly.ReplicaNotCreated",
428
+ }),
429
+ );
430
+ current = yield* machines
431
+ .createMachine({
432
+ app_name: input.appName,
433
+ name,
434
+ region: regionOfReplica(input.regions, index),
435
+ config: {
436
+ ...pinnedConfig,
437
+ image: containerPins ? undefined : (image ?? config.image),
438
+ services: run ? preparationServices : config.services,
439
+ },
440
+ skip_launch: !run,
441
+ skip_service_registration: true,
442
+ min_secrets_version: input.minSecretsVersion,
443
+ })
444
+ .pipe(
445
+ Retry.none,
446
+ Effect.timeout("30 seconds"),
447
+ Effect.catchTag(["Conflict", "GatewayTimeout", "TimeoutError"], () => readback),
448
+ Effect.catchReason("HttpClientError", "TransportError", () => readback),
449
+ );
450
+ }
451
+ if (!current?.id)
452
+ return yield* new ReplicaNotCreated({ appName: input.appName, resourceName: name });
453
+ const leased = (yield* leaseSnapshot(input.appName, [current], leases))[0];
454
+ if (!leased?.id)
455
+ return yield* ambiguous(
456
+ `Candidate ${current.id} disappeared before its lease was acquired.`,
457
+ );
458
+ const mismatch = mismatchOf(leased);
459
+ if (mismatch !== undefined)
460
+ return yield* ambiguous(
461
+ `Candidate ${current.id} changed before its lease was acquired. Mismatch: ${mismatch}.`,
462
+ );
463
+ current = leased;
464
+ snapshotIds.add(current.id);
465
+ if (containerPins) {
466
+ if (
467
+ !validObservedImageSet(current) ||
468
+ !sameImageSet(pinsFromConfig(current.config), containerPins)
469
+ )
470
+ return yield* ambiguous(`Container image pin mismatch on ${current.id}.`);
471
+ } else {
472
+ const resolvedImage = pinnedImage(current);
473
+ if (!resolvedImage || (image !== undefined && image !== resolvedImage))
474
+ return yield* ambiguous(`Image pin mismatch on ${current.id}.`);
475
+ image = resolvedImage;
476
+ if (current.config?.metadata?.[keys.image] !== image)
477
+ yield* setMetadata(
478
+ input.appName,
479
+ current,
480
+ { ...metadataOf(current), [keys.image]: image },
481
+ leases,
482
+ );
483
+ }
484
+ const checked =
485
+ current.config?.metadata?.[keys.checkedInstance] === current.instance_id &&
486
+ current.instance_id !== undefined;
487
+ if (roles[index] === "run" && !(idleAllowed && checked && idle(current))) {
488
+ current = yield* ensureStarted(
489
+ input.appName,
490
+ current,
491
+ false,
492
+ input.policy.healthTimeoutMs,
493
+ current.config,
494
+ leases,
495
+ );
496
+ } else if (!idle(current)) {
497
+ current = yield* waitHealthy(
498
+ input.appName,
499
+ current,
500
+ input.policy.healthTimeoutMs,
501
+ current.config,
502
+ );
503
+ }
504
+ candidates[index] = current;
505
+ }
506
+ }).pipe(
507
+ Effect.catch((error) =>
508
+ Effect.gen(function* () {
509
+ const found = (yield* observe).filter(
510
+ (machine) =>
511
+ snapshotIds.has(machine.id) &&
512
+ machine.config?.metadata?.[keys.generation] === generation,
513
+ );
514
+ // A possibly promoted candidate is capacity, not rollback garbage.
515
+ if (
516
+ found.every(
517
+ (machine) =>
518
+ (!containerMode || matches(machine)) &&
519
+ machine.config?.metadata?.[keys.phase] === "candidate" &&
520
+ machine.cordoned === true,
521
+ )
522
+ ) {
523
+ yield* Effect.forEach(
524
+ found,
525
+ (machine) =>
526
+ deleteMachine(input.appName, machine.id!, leases).pipe(
527
+ Effect.catch((cleanup) =>
528
+ Effect.logWarning("Fly candidate cleanup remains pending", {
529
+ appName: input.appName,
530
+ machineId: machine.id,
531
+ error: cleanup._tag,
532
+ }),
533
+ ),
534
+ ),
535
+ { concurrency: 4 },
536
+ );
537
+ }
538
+ return yield* error;
539
+ }),
540
+ ),
541
+ );
542
+
543
+ const needsPromotion = candidates.some(
544
+ (machine) => machine.cordoned !== false || machine.config?.metadata?.[keys.phase] !== "active",
545
+ );
546
+ if (needsPromotion) {
547
+ for (const machine of candidates) yield* phase(input.appName, machine, "promoting", leases);
548
+ // Promotion metadata resets reports; validate the whole set before routing any member.
549
+ for (const [index, machine] of candidates.entries()) {
550
+ const current = yield* getMachineById(input.appName, machine.id!);
551
+ if (!current || !matches(current))
552
+ return yield* ambiguous(`Candidate ${machine.id} changed before promotion.`);
553
+ if (current.state === "started") {
554
+ candidates[index] = yield* waitHealthy(
555
+ input.appName,
556
+ current,
557
+ input.policy.healthTimeoutMs,
558
+ current.config,
559
+ );
560
+ } else if (
561
+ !idleAllowed ||
562
+ !idle(current) ||
563
+ (roles[index] === "run" &&
564
+ (current.instance_id === undefined ||
565
+ current.config?.metadata?.[keys.checkedInstance] !== current.instance_id))
566
+ ) {
567
+ return yield* ambiguous(`Candidate ${machine.id} has no readiness proof before promotion.`);
568
+ } else candidates[index] = current;
569
+ }
570
+ for (const machine of candidates)
571
+ if (machine.cordoned !== false) yield* setRouting(input.appName, machine.id!, false, leases);
572
+ if (hasPublishedService(config.services)) yield* Effect.sleep("10 seconds");
573
+ }
574
+ for (const [index, machine] of candidates.entries()) {
575
+ let current = machine;
576
+ if (current.config?.metadata?.[keys.restored] === "false") {
577
+ // Restoring services creates a new instance; its predecessor's checks cannot prove readiness.
578
+ const machineId = current.id!;
579
+ const currentVersion = current.instance_id;
580
+ const restoreConfig = input.buildConfig({
581
+ index,
582
+ mounts: [],
583
+ metadata: { ...metadataOf(current), [keys.restored]: "true" },
584
+ });
585
+ const restored = containerPins
586
+ ? applyImageSet(restoreConfig, containerPins)
587
+ : { ...restoreConfig, image };
588
+ if (restored === undefined)
589
+ return yield* ambiguous("Incomplete image set during service restoration.");
590
+ current = yield* leases.mutate(machineId, (lease_nonce) =>
591
+ machines
592
+ .updateMachine({
593
+ app_name: input.appName,
594
+ machine_id: machineId,
595
+ lease_nonce,
596
+ current_version: currentVersion,
597
+ config: restored,
598
+ min_secrets_version: input.minSecretsVersion,
599
+ })
600
+ .pipe(Effect.timeout("30 seconds")),
601
+ );
602
+ current = yield* ensureStarted(
603
+ input.appName,
604
+ current,
605
+ false,
606
+ input.policy.healthTimeoutMs,
607
+ config,
608
+ leases,
609
+ );
610
+ } else {
611
+ current = (yield* getMachineById(input.appName, current.id!)) ?? current;
612
+ if (current.instance_id !== machine.instance_id) {
613
+ current = yield* ensureStarted(
614
+ input.appName,
615
+ current,
616
+ false,
617
+ input.policy.healthTimeoutMs,
618
+ config,
619
+ leases,
620
+ );
621
+ }
622
+ if (
623
+ current.state !== "started" &&
624
+ roles[index] === "run" &&
625
+ current.config?.metadata?.[keys.checkedInstance] !== current.instance_id
626
+ ) {
627
+ current = yield* ensureStarted(
628
+ input.appName,
629
+ current,
630
+ false,
631
+ input.policy.healthTimeoutMs,
632
+ config,
633
+ leases,
634
+ );
635
+ }
636
+ }
637
+ candidates[index] = current;
638
+ }
639
+ // Reset reports while still pending; an interrupted validation is not a commit.
640
+ for (const machine of candidates) yield* phase(input.appName, machine, "validating", leases);
641
+ for (const [index, machine] of candidates.entries()) {
642
+ const current = yield* getMachineById(input.appName, machine.id!);
643
+ if (!current || !matches(current) || current.config?.metadata?.[keys.restored] !== "true")
644
+ return yield* ambiguous(`Candidate ${machine.id} changed before commitment.`);
645
+ if (current.state === "started")
646
+ candidates[index] = yield* waitHealthy(
647
+ input.appName,
648
+ current,
649
+ input.policy.healthTimeoutMs,
650
+ config,
651
+ );
652
+ else if (
653
+ !idleAllowed ||
654
+ !idle(current) ||
655
+ (roles[index] === "run" &&
656
+ (current.instance_id === undefined ||
657
+ (current.config?.metadata?.[keys.checkedInstance] !== current.instance_id &&
658
+ !(machine.instance_id === current.instance_id && checksPassing(machine, config)))))
659
+ ) {
660
+ return yield* ambiguous(
661
+ `Candidate ${machine.id} has no readiness proof for its current instance.`,
662
+ );
663
+ } else candidates[index] = current;
664
+ }
665
+ // All final checks precede the commit stamps, with replica zero last.
666
+ for (const machine of [...candidates].reverse()) {
667
+ const committed = {
668
+ ...metadataOf(machine),
669
+ [keys.phase]: "active",
670
+ ...(machine.state === "started" || roles[replicaIndexOf(machine)] === "run"
671
+ ? { [keys.checkedInstance]: machine.instance_id! }
672
+ : {}),
673
+ };
674
+ if (!deepEqual(metadataOf(machine), committed))
675
+ yield* setMetadata(input.appName, machine, committed, leases);
676
+ }
677
+ // Legacy ownership is required; predecessor phase stamps are only advisory.
678
+ for (const machine of predecessors) {
679
+ if (machine.config?.metadata?.[keys.protocol] === "2") {
680
+ const observed = yield* getMachineById(input.appName, machine.id!);
681
+ if (
682
+ !observed ||
683
+ observed.config?.metadata?.[keys.protocol] !== "2" ||
684
+ !validObservedImageSet(observed) ||
685
+ !sameImageSet(pinsFromConfig(observed.config), pinsFromConfig(machine.config))
686
+ )
687
+ return yield* ambiguous(
688
+ `Predecessor ${machine.id} image identity changed before retirement.`,
689
+ );
690
+ }
691
+ if (machine.config?.metadata?.[keys.instance] === undefined)
692
+ yield* setMetadata(input.appName, machine, { ...metadataOf(machine), ...metadata }, leases);
693
+ if (machine.host_status !== "unreachable")
694
+ yield* phase(input.appName, machine, "retiring", leases).pipe(
695
+ Effect.catch((error) =>
696
+ Effect.logWarning("Fly predecessor phase metadata was not updated", {
697
+ appName: input.appName,
698
+ machineId: machine.id,
699
+ error: error._tag,
700
+ }),
701
+ ),
702
+ );
703
+ }
704
+ yield* retireMachines(input.appName, predecessors, true, leases);
705
+ return toReplicaSet(
706
+ candidates.map((machine) => toReplica(machine, new Map())),
707
+ input.appName,
708
+ input.baseName,
709
+ config.services,
710
+ );
711
+ });