@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,777 @@
1
+ import {
2
+ diffMigrations,
3
+ migrationsAttrs,
4
+ migrationsInputOf,
5
+ stampedOf,
6
+ type MigrationsInput,
7
+ } from "@alchemy.run/sql/Migrations";
8
+ import { hashImports } from "@alchemy.run/sql/SqlFile";
9
+ import * as machines from "@distilled.cloud/fly-io/machines";
10
+ import type {
11
+ ClusterCredentials,
12
+ GetClusterResponse,
13
+ ManagedCluster,
14
+ } from "@distilled.cloud/fly-io/mpg";
15
+ import * as mpg from "@distilled.cloud/fly-io/mpg";
16
+ import { Unowned } from "alchemy/AdoptPolicy";
17
+ import { isResolved } from "alchemy/Diff";
18
+ import * as Provider from "alchemy/Provider";
19
+ import { Resource } from "alchemy/Resource";
20
+ import { recordsEqual } from "alchemy/Util/equal";
21
+ import * as Data from "effect/Data";
22
+ import * as Duration from "effect/Duration";
23
+ import * as Effect from "effect/Effect";
24
+ import * as Redacted from "effect/Redacted";
25
+ import * as Schedule from "effect/Schedule";
26
+ import { resolveOrgSlug } from "./Environment.ts";
27
+ import { createFlyAppName, matchesAlchemyPhysicalName, sanitizeFlyAppName } from "./Metadata.ts";
28
+ import { runImports, runPgMigrations } from "./PostgresMigrations.ts";
29
+ import type { Providers } from "./Providers.ts";
30
+
31
+ export { stripSslQueryParams } from "./PostgresMigrations.ts";
32
+
33
+ export const DEFAULT_POSTGRES_PLAN = "basic";
34
+ export const DEFAULT_VOLUME_GB = 10;
35
+ export const DATABASE_URL_SECRET = "DATABASE_URL";
36
+ export const DIRECT_DATABASE_URL_SECRET = "DIRECT_DATABASE_URL";
37
+
38
+ export type PostgresPlan = "basic" | "starter" | "launch" | "scale" | "performance" | (string & {});
39
+
40
+ export interface PostgresProps {
41
+ /**
42
+ * Region the cluster lives in (`iad`, `ord`, `sjc`, …). Required.
43
+ * The cluster is regional; a {@link App} is global. Changing it
44
+ * replaces the cluster.
45
+ */
46
+ region: string;
47
+ /**
48
+ * Hardware plan. `basic` is 2 shared vCPUs / 1 GB RAM.
49
+ *
50
+ * @default "basic"
51
+ */
52
+ plan?: PostgresPlan;
53
+ /**
54
+ * Cluster name. Unique in the organization. If omitted, a unique
55
+ * name is generated from the stack, stage and logical ID. Changing
56
+ * it replaces the cluster.
57
+ */
58
+ name?: string;
59
+ /**
60
+ * Organization slug. Defaults to the current token's org. Changing
61
+ * it replaces the cluster.
62
+ */
63
+ orgSlug?: string;
64
+ /**
65
+ * Initial volume size in GB. Fly defaults to 10. Create-only.
66
+ *
67
+ * @default 10
68
+ */
69
+ volumeSizeGb?: number;
70
+ /**
71
+ * Enable PostGIS. Create-only.
72
+ *
73
+ * @default false
74
+ */
75
+ postgis?: boolean;
76
+ /**
77
+ * Postgres major version (`16` or `17`). Create-only.
78
+ *
79
+ * @default 16
80
+ */
81
+ pgMajorVersion?: number | string;
82
+ /**
83
+ * SQL migrations to apply against the cluster. Accepts a directory
84
+ * path, a `Drizzle.Schema` resource, or `{ dir, table? }`.
85
+ *
86
+ * Bookkeeping always lives in Alchemy's `__alchemy_migrations` table. A
87
+ * database previously migrated by drizzle-kit or Prisma is adopted by a
88
+ * one-way conversion on first deploy: the old tool's applied history is
89
+ * copied into Alchemy's table and the old table is left frozen. No
90
+ * baselining required.
91
+ *
92
+ * Applied over the **direct** (non-PgBouncer) URI. Fly Managed Postgres
93
+ * is reachable on the org private network; deploy-time apply needs a
94
+ * route to that network (a WireGuard peer, `fly mpg proxy`, or a
95
+ * machine already on 6PN).
96
+ */
97
+ migrations?: MigrationsInput;
98
+ /**
99
+ * Paths to additional `.sql` files to apply after migrations. Each file
100
+ * is hashed; only files whose contents change are re-applied on
101
+ * subsequent deploys.
102
+ */
103
+ importFiles?: string[];
104
+ }
105
+
106
+ export type Postgres = Resource<
107
+ "Fly.Postgres",
108
+ PostgresProps,
109
+ {
110
+ /** Fly Managed Postgres cluster id. */
111
+ clusterId: string;
112
+ /** Cluster name (unique in the org). */
113
+ name: string;
114
+ /** Observed status (`creating`, `ready`, `error`, `deleted`, …). */
115
+ status: string | undefined;
116
+ /** Region the cluster lives in. */
117
+ region: string;
118
+ /** Observed hardware plan. */
119
+ plan: string | undefined;
120
+ /** Organization slug. */
121
+ orgSlug: string | undefined;
122
+ /** Observed disk size in GB. */
123
+ disk: number | undefined;
124
+ /** Whether PostGIS is enabled. */
125
+ postgisEnabled: boolean | undefined;
126
+ /** Observed engine string, if the API returned one. */
127
+ engine: string | undefined;
128
+ /** Observed replica count. */
129
+ replicas: number | undefined;
130
+ /** Internal MPG cluster hash id, if the API returned one. */
131
+ mpgdClusterId: string | undefined;
132
+ /**
133
+ * Direct (non-PgBouncer) Postgres URI. Use this for migrations and
134
+ * session-scoped features. Pass to `Drizzle.Postgres` from a laptop
135
+ * Action; from a {@link Service} prefer {@link ConnectPostgres}.
136
+ */
137
+ connectionUri: string;
138
+ /** Pooled PgBouncer URI. Prefer {@link ConnectPostgres} from a Service. */
139
+ pooledConnectionUri: string;
140
+ migrationsDir: string | undefined;
141
+ migrationsTable: string | undefined;
142
+ migrationsHashes: Record<string, string>;
143
+ importHashes: Record<string, string>;
144
+ },
145
+ never,
146
+ Providers
147
+ >;
148
+
149
+ /**
150
+ * A Fly.Postgres is a Managed Postgres (MPG) cluster. It is billed.
151
+ * Do not wrap unmanaged `fly postgres`.
152
+ *
153
+ * @see https://fly.io/docs/mpg/create-and-connect/
154
+ *
155
+ * ### Create a cluster
156
+ * `region` is required. Alchemy generates a unique name unless you
157
+ * pass one. Omit `name` in tests and CI.
158
+ *
159
+ * **Example:** Generated name
160
+ * ```typescript
161
+ * const db = yield* Fly.Postgres("Db", {
162
+ * region: "iad",
163
+ * });
164
+ * ```
165
+ *
166
+ * :::caution[Billed]
167
+ * Managed Postgres is billed. Basic is about $38 per month.
168
+ * :::
169
+ *
170
+ * ### Plan
171
+ * `plan` is the hardware size: `basic`, `starter`, `launch`,
172
+ * `scale`, `performance`. Default is `basic`.
173
+ *
174
+ * **Example:** Starter
175
+ * ```typescript
176
+ * const db = yield* Fly.Postgres("Db", {
177
+ * region: "iad",
178
+ * plan: "starter",
179
+ * });
180
+ * ```
181
+ *
182
+ * :::note[Create-only]
183
+ * Changing `plan` later is ignored. Fly has no cluster update API.
184
+ * :::
185
+ *
186
+ * ### Region
187
+ * The cluster is regional. An {@link App} is global. Pass `region`
188
+ * on the cluster, not on the App.
189
+ *
190
+ * **Example:** Pin a region
191
+ * ```typescript
192
+ * const db = yield* Fly.Postgres("Db", {
193
+ * region: "lhr",
194
+ * });
195
+ * ```
196
+ *
197
+ * :::caution[Changing `region` replaces the cluster]
198
+ * A new cluster is created in the new region. The old cluster is
199
+ * deleted. Data is not copied.
200
+ * :::
201
+ *
202
+ * ### Volume size
203
+ * `volumeSizeGb` is the initial disk. Fly defaults to 10 GB.
204
+ *
205
+ * **Example:** 20 GB
206
+ * ```typescript
207
+ * const db = yield* Fly.Postgres("Db", {
208
+ * region: "iad",
209
+ * volumeSizeGb: 20,
210
+ * });
211
+ * ```
212
+ *
213
+ * :::note[Create-only]
214
+ * Changing `volumeSizeGb` later is ignored.
215
+ * :::
216
+ *
217
+ * ### PostGIS
218
+ * `postgis: true` enables PostGIS at create.
219
+ *
220
+ * **Example:** Enable PostGIS
221
+ * ```typescript
222
+ * const db = yield* Fly.Postgres("Db", {
223
+ * region: "iad",
224
+ * postgis: true,
225
+ * });
226
+ * ```
227
+ *
228
+ * :::note[Create-only]
229
+ * Flipping `postgis` later is ignored.
230
+ * :::
231
+ *
232
+ * ### Connect from a Service
233
+ * Yield `ConnectPostgres` inside init. Provide
234
+ * {@link ConnectPostgresHttp}. Pass `conn.connectionString` to
235
+ * `Drizzle.Postgres` or `SQL.Postgres`.
236
+ *
237
+ * **Example:** Bind and query
238
+ * ```typescript
239
+ * import * as Drizzle from "@alchemy.run/drizzle/Postgres";
240
+ * import * as HttpServerResponse from "effect/http/HttpServerResponse";
241
+ *
242
+ * export default class Api extends Fly.Service<Api>()(
243
+ * "Api",
244
+ * { app: Site, main: import.meta.url, port: 3000 },
245
+ * Effect.gen(function* () {
246
+ * const conn = yield* Fly.ConnectPostgres(Db);
247
+ * const db = yield* Drizzle.Postgres(conn.connectionString);
248
+ * return {
249
+ * fetch: Effect.gen(function* () {
250
+ * const rows = yield* db.execute("select 1 as ok");
251
+ * return HttpServerResponse.json({ rows });
252
+ * }),
253
+ * };
254
+ * }).pipe(Effect.provide(Fly.ConnectPostgresHttp)),
255
+ * ) {}
256
+ * ```
257
+ *
258
+ * ### Migrations
259
+ * Pass a directory, `{ dir, table? }`, or a `Drizzle.Schema` resource.
260
+ * Alchemy applies pending files on deploy over the direct URI.
261
+ *
262
+ * **Example:** Directory
263
+ * ```typescript
264
+ * const db = yield* Fly.Postgres("Db", {
265
+ * region: "iad",
266
+ * migrations: "./migrations",
267
+ * });
268
+ * ```
269
+ *
270
+ * **Example:** Drizzle.Schema
271
+ * ```typescript
272
+ * const schema = yield* Drizzle.Schema("app-schema", {
273
+ * schema: "./src/schema.ts",
274
+ * out: "./migrations",
275
+ * });
276
+ *
277
+ * const db = yield* Fly.Postgres("Db", {
278
+ * region: "iad",
279
+ * migrations: schema,
280
+ * });
281
+ * ```
282
+ *
283
+ * @resource
284
+ * @product Postgres
285
+ */
286
+ export const Postgres = Resource<Postgres>("Fly.Postgres");
287
+
288
+ export class PostgresNotCreated extends Data.TaggedError("Fly.PostgresNotCreated")<{
289
+ resourceName: string;
290
+ orgSlug: string;
291
+ }> {}
292
+
293
+ export class PostgresCreateFailed extends Data.TaggedError("Fly.PostgresCreateFailed")<{
294
+ clusterId: string;
295
+ status: string;
296
+ }> {}
297
+
298
+ export class PostgresCredentialsMissing extends Data.TaggedError("Fly.PostgresCredentialsMissing")<{
299
+ clusterId: string;
300
+ }> {}
301
+
302
+ export class PostgresAttachmentFailed extends Data.TaggedError("Fly.PostgresAttachmentFailed")<{
303
+ clusterId: string;
304
+ appName: string;
305
+ }> {}
306
+
307
+ class PostgresPending extends Data.TaggedError("Fly.PostgresPending")<{
308
+ clusterId: string;
309
+ status: string;
310
+ }> {}
311
+
312
+ const backoff = Schedule.min([
313
+ Schedule.exponential(Duration.millis(500), 1.5),
314
+ Schedule.spaced(Duration.seconds(5)),
315
+ ]);
316
+
317
+ export const isLiveCluster = (cluster: ManagedCluster | undefined): cluster is ManagedCluster =>
318
+ cluster !== undefined && (cluster.id ?? "").length > 0 && cluster.status !== "deleted";
319
+
320
+ export const unwrapSensitive = (
321
+ value: string | Redacted.Redacted<string> | undefined,
322
+ ): string | undefined => {
323
+ if (value === undefined) return undefined;
324
+ return Redacted.isRedacted(value) ? Redacted.value(value) : value;
325
+ };
326
+
327
+ type AttrFallback = {
328
+ name?: string;
329
+ orgSlug?: string;
330
+ connectionUri?: string;
331
+ pooledConnectionUri?: string;
332
+ migrationsDir?: string | undefined;
333
+ migrationsTable?: string | undefined;
334
+ migrationsHashes?: Record<string, string>;
335
+ importHashes?: Record<string, string>;
336
+ };
337
+
338
+ const toAttrs = (
339
+ cluster: ManagedCluster,
340
+ fallback?: AttrFallback,
341
+ credentials?: ClusterCredentials,
342
+ ): Postgres["Attributes"] => ({
343
+ clusterId: cluster.id ?? "",
344
+ name: cluster.name ?? fallback?.name ?? "",
345
+ status: cluster.status,
346
+ region: cluster.region ?? "",
347
+ plan: cluster.plan,
348
+ orgSlug: cluster.organization?.slug ?? fallback?.orgSlug,
349
+ disk: cluster.disk,
350
+ postgisEnabled: cluster.postgis_enabled,
351
+ engine: cluster.engine,
352
+ replicas: cluster.replicas,
353
+ mpgdClusterId: cluster.mpgd_cluster_id,
354
+ connectionUri: directUri(cluster, credentials) ?? fallback?.connectionUri ?? "",
355
+ pooledConnectionUri: credentialsUri(credentials) ?? fallback?.pooledConnectionUri ?? "",
356
+ migrationsDir: fallback?.migrationsDir,
357
+ migrationsTable: fallback?.migrationsTable,
358
+ migrationsHashes: fallback?.migrationsHashes ?? {},
359
+ importHashes: fallback?.importHashes ?? {},
360
+ });
361
+
362
+ const resolveName = (id: string, name: string | undefined, existing?: string) =>
363
+ Effect.gen(function* () {
364
+ if (name !== undefined) return sanitizeFlyAppName(name);
365
+ if (existing !== undefined) return existing;
366
+ return yield* createFlyAppName(id);
367
+ });
368
+
369
+ export const getLiveCluster = (clusterId: string) =>
370
+ mpg.getClusterById({ id: clusterId }).pipe(
371
+ Effect.map((res) => (isLiveCluster(res.data) ? res.data : undefined)),
372
+ Effect.catchTag("NotFound", () => Effect.undefined),
373
+ );
374
+
375
+ export const getClusterResponse = (clusterId: string) =>
376
+ mpg.getClusterById({ id: clusterId }).pipe(
377
+ Effect.map((res): GetClusterResponse | undefined =>
378
+ isLiveCluster(res.data) ? res : undefined,
379
+ ),
380
+ Effect.catchTag("NotFound", () => Effect.undefined),
381
+ );
382
+
383
+ const listOrgClusters = (orgSlug: string) =>
384
+ mpg.listClusters({ org_slug: orgSlug }).pipe(
385
+ Effect.map((res) => (res.data ?? []).filter((row) => isLiveCluster(row))),
386
+ Effect.catchTag(["NotFound", "Forbidden"], () => Effect.succeed([] as ManagedCluster[])),
387
+ );
388
+
389
+ const findByName = (orgSlug: string, name: string) =>
390
+ listOrgClusters(orgSlug).pipe(Effect.map((rows) => rows.find((row) => row.name === name)));
391
+
392
+ const waitUntilReady = (clusterId: string) =>
393
+ getLiveCluster(clusterId).pipe(
394
+ Effect.flatMap(
395
+ (cluster): Effect.Effect<ManagedCluster, PostgresPending | PostgresCreateFailed> => {
396
+ if (cluster === undefined) {
397
+ return Effect.fail(new PostgresPending({ clusterId, status: "missing" }));
398
+ }
399
+ if (cluster.status === "ready") return Effect.succeed(cluster);
400
+ if (cluster.status === "error") {
401
+ return Effect.fail(
402
+ new PostgresCreateFailed({
403
+ clusterId,
404
+ status: cluster.status,
405
+ }),
406
+ );
407
+ }
408
+ return Effect.fail(
409
+ new PostgresPending({
410
+ clusterId,
411
+ status: cluster.status ?? "creating",
412
+ }),
413
+ );
414
+ },
415
+ ),
416
+ Effect.retry({
417
+ while: (e) => e._tag === "Fly.PostgresPending",
418
+ times: 10,
419
+ schedule: backoff,
420
+ }),
421
+ Effect.catchTag("Fly.PostgresPending", () => getLiveCluster(clusterId)),
422
+ );
423
+
424
+ const waitForCredentials = (clusterId: string) =>
425
+ getClusterResponse(clusterId).pipe(
426
+ Effect.flatMap((res) => {
427
+ const uri = credentialsUri(res?.credentials);
428
+ if (uri !== undefined && uri.length > 0) {
429
+ return Effect.succeed(res);
430
+ }
431
+ return Effect.fail(new PostgresCredentialsPending({ clusterId }));
432
+ }),
433
+ Effect.retry({
434
+ while: (e) => e._tag === "Fly.PostgresCredentialsPending",
435
+ times: 16,
436
+ schedule: backoff,
437
+ }),
438
+ Effect.catchTag("Fly.PostgresCredentialsPending", () => getClusterResponse(clusterId)),
439
+ );
440
+
441
+ const waitUntilGone = (clusterId: string) =>
442
+ mpg.getClusterById({ id: clusterId }).pipe(
443
+ Effect.map((res) => res.data === undefined || res.data.status === "deleted"),
444
+ Effect.catchTag("NotFound", () => Effect.succeed(true)),
445
+ Effect.repeat({
446
+ schedule: Schedule.spaced("2 seconds"),
447
+ until: (gone) => gone,
448
+ times: 10,
449
+ }),
450
+ );
451
+
452
+ const desiredPlan = (plan: PostgresPlan | undefined) => plan ?? DEFAULT_POSTGRES_PLAN;
453
+
454
+ const desiredDisk = (size: number | undefined) =>
455
+ size === undefined ? DEFAULT_VOLUME_GB : Math.max(1, size);
456
+
457
+ const pgMajor = (value: number | string | undefined) =>
458
+ value === undefined ? undefined : String(value);
459
+
460
+ export const credentialsUri = (credentials: ClusterCredentials | undefined): string | undefined =>
461
+ unwrapSensitive(credentials?.pgbouncer_uri);
462
+
463
+ export const directUri = (
464
+ _cluster: ManagedCluster | undefined,
465
+ credentials: ClusterCredentials | undefined,
466
+ ): string | undefined => {
467
+ // Derive the direct host from the server-provided PgBouncer URI:
468
+ // `pgbouncer.<hash>.flympg.net` → `direct.<hash>.flympg.net`. The `<hash>`
469
+ // is the cluster's DNS hash, which is NOT any id the cluster API returns —
470
+ // `mpgd_cluster_id` is the `fly-mpg-…` cluster id, and a host synthesized
471
+ // from it does not resolve. Rewriting the observed pooled host is the only
472
+ // reliable derivation.
473
+ const pooled = unwrapSensitive(credentials?.pgbouncer_uri);
474
+ if (pooled === undefined || pooled.length === 0) return undefined;
475
+ try {
476
+ const url = new URL(pooled);
477
+ if (!url.hostname.startsWith("pgbouncer.")) return undefined;
478
+ url.hostname = url.hostname.replace(/^pgbouncer\./, "direct.");
479
+ return url.toString();
480
+ } catch {
481
+ return undefined;
482
+ }
483
+ };
484
+
485
+ const secretVersion = (res: { version?: number; Version?: number } | undefined) =>
486
+ res?.version ?? res?.Version;
487
+
488
+ const putSecret = (appName: string, name: string, value: string) =>
489
+ machines
490
+ .createSecret({
491
+ app_name: appName,
492
+ secret_name: name,
493
+ value,
494
+ })
495
+ .pipe(
496
+ Effect.map(secretVersion),
497
+ Effect.catchTag("Conflict", () =>
498
+ machines
499
+ .updateSecrets({
500
+ app_name: appName,
501
+ values: { [name]: value },
502
+ })
503
+ .pipe(Effect.map(secretVersion)),
504
+ ),
505
+ );
506
+
507
+ class PostgresCredentialsPending extends Data.TaggedError("Fly.PostgresCredentialsPending")<{
508
+ clusterId: string;
509
+ }> {}
510
+
511
+ /**
512
+ * Write `DATABASE_URL` (and `DIRECT_DATABASE_URL` if present) onto an
513
+ * App and record the MPG attachment. Called from {@link Service}
514
+ * reconcile when {@link ConnectPostgres} binds a cluster.
515
+ */
516
+ export const attachPostgresSecrets = Effect.fn(function* (
517
+ appName: string,
518
+ clusterId: string,
519
+ variableName: string = DATABASE_URL_SECRET,
520
+ ) {
521
+ if (appName.length === 0 || clusterId.length === 0) return undefined;
522
+ const creds = yield* getClusterResponse(clusterId).pipe(
523
+ Effect.flatMap((res) => {
524
+ const uri = credentialsUri(res?.credentials);
525
+ if (uri !== undefined && uri.length > 0) {
526
+ return Effect.succeed({
527
+ uri,
528
+ direct: directUri(res?.data, res?.credentials),
529
+ });
530
+ }
531
+ return Effect.fail(new PostgresCredentialsPending({ clusterId }));
532
+ }),
533
+ Effect.retry({
534
+ while: (e) => e._tag === "Fly.PostgresCredentialsPending",
535
+ times: 10,
536
+ schedule: backoff,
537
+ }),
538
+ Effect.catchTag("Fly.PostgresCredentialsPending", () => Effect.undefined),
539
+ );
540
+ if (creds === undefined) {
541
+ return yield* new PostgresCredentialsMissing({ clusterId });
542
+ }
543
+ const versions: number[] = [];
544
+ const pooledVersion = yield* putSecret(appName, variableName, creds.uri);
545
+ if (pooledVersion !== undefined) versions.push(pooledVersion);
546
+ if (creds.direct !== undefined) {
547
+ const directVersion = yield* putSecret(appName, DIRECT_DATABASE_URL_SECRET, creds.direct);
548
+ if (directVersion !== undefined) versions.push(directVersion);
549
+ }
550
+ yield* mpg
551
+ .createAttachment({
552
+ id: clusterId,
553
+ app_name: appName,
554
+ })
555
+ .pipe(
556
+ Effect.asVoid,
557
+ Effect.catchTag("Conflict", () => Effect.void),
558
+ Effect.retry({
559
+ while: (e) => e._tag === "NotFound",
560
+ times: 8,
561
+ schedule: backoff,
562
+ }),
563
+ Effect.timeout("40 seconds"),
564
+ Effect.catchTag(
565
+ "NotFound",
566
+ () =>
567
+ new PostgresAttachmentFailed({
568
+ clusterId,
569
+ appName,
570
+ }),
571
+ ),
572
+ );
573
+ return versions.length > 0 ? Math.max(...versions) : undefined;
574
+ });
575
+
576
+ const rootDir = Effect.sync(() => process.cwd());
577
+
578
+ export const PostgresProvider = () =>
579
+ Provider.succeed(Postgres, {
580
+ stables: ["clusterId", "name", "region", "orgSlug"],
581
+ nuke: { dependsOn: ["Fly.App"] },
582
+
583
+ diff: Effect.fn(function* ({ news, output }) {
584
+ if (news === undefined || !isResolved(news)) return undefined;
585
+ if (output === undefined) return undefined;
586
+ const desiredName = news.name !== undefined ? sanitizeFlyAppName(news.name) : output.name;
587
+ const nameChanged = desiredName !== output.name;
588
+ const regionChanged = news.region !== output.region;
589
+ const orgChanged = news.orgSlug !== undefined && news.orgSlug !== output.orgSlug;
590
+ if (nameChanged || regionChanged || orgChanged) {
591
+ return { action: "replace" as const };
592
+ }
593
+ if (yield* diffMigrations({ news, output })) {
594
+ return { action: "update" as const };
595
+ }
596
+ if (news.importFiles?.length) {
597
+ const newHashes = yield* hashImports(news.importFiles, yield* rootDir);
598
+ if (!recordsEqual(newHashes, output.importHashes ?? {})) {
599
+ return { action: "update" as const };
600
+ }
601
+ }
602
+ return undefined;
603
+ }),
604
+
605
+ read: Effect.fn(function* ({ id, olds, output }) {
606
+ const found =
607
+ output?.clusterId !== undefined && output.clusterId.length > 0
608
+ ? yield* getClusterResponse(output.clusterId)
609
+ : undefined;
610
+ if (found?.data !== undefined) {
611
+ return toAttrs(found.data, output, found.credentials);
612
+ }
613
+ const name = yield* resolveName(id, olds?.name, output?.name);
614
+ const orgSlug = olds?.orgSlug ?? output?.orgSlug ?? (yield* resolveOrgSlug());
615
+ const byName = yield* findByName(orgSlug, name);
616
+ if (byName === undefined) return undefined;
617
+ const hydrated = byName.id !== undefined ? yield* getClusterResponse(byName.id) : undefined;
618
+ const attrs = toAttrs(
619
+ hydrated?.data ?? byName,
620
+ { ...output, name, orgSlug },
621
+ hydrated?.credentials,
622
+ );
623
+ if (output !== undefined) return attrs;
624
+ return matchesAlchemyPhysicalName(name) ? attrs : Unowned(attrs);
625
+ }),
626
+
627
+ list: Effect.fn(function* () {
628
+ const orgSlug = yield* resolveOrgSlug();
629
+ const rows = yield* listOrgClusters(orgSlug);
630
+ return rows.flatMap((cluster) => {
631
+ if (!matchesAlchemyPhysicalName(cluster.name)) return [];
632
+ return [
633
+ toAttrs(cluster, {
634
+ orgSlug,
635
+ migrationsDir: undefined,
636
+ migrationsTable: undefined,
637
+ migrationsHashes: {},
638
+ importHashes: {},
639
+ }),
640
+ ];
641
+ });
642
+ }),
643
+
644
+ reconcile: Effect.fn(function* ({ id, news, output }) {
645
+ const props = news ?? ({} as PostgresProps);
646
+ const name = yield* resolveName(id, props.name, output?.name);
647
+ const orgSlug = props.orgSlug ?? (yield* resolveOrgSlug());
648
+ const region = props.region ?? output?.region;
649
+
650
+ let current =
651
+ output?.clusterId !== undefined && output.clusterId.length > 0
652
+ ? yield* getLiveCluster(output.clusterId)
653
+ : undefined;
654
+ if (
655
+ current === undefined &&
656
+ (output === undefined || output.name !== name || output.orgSlug !== orgSlug)
657
+ ) {
658
+ current = yield* findByName(orgSlug, name);
659
+ }
660
+
661
+ if (current === undefined) {
662
+ if (region === undefined || region.length === 0) {
663
+ return yield* new PostgresNotCreated({ resourceName: name, orgSlug });
664
+ }
665
+ const created = yield* mpg
666
+ .createCluster({
667
+ org_slug: orgSlug,
668
+ name,
669
+ region,
670
+ plan: desiredPlan(props.plan),
671
+ storage_in_gb: desiredDisk(props.volumeSizeGb),
672
+ postgis_enabled: props.postgis,
673
+ pg_major_version: pgMajor(props.pgMajorVersion),
674
+ })
675
+ .pipe(
676
+ Effect.map((res) => res.data),
677
+ Effect.catchTag("Conflict", () => Effect.undefined),
678
+ );
679
+ current = isLiveCluster(created) ? created : yield* findByName(orgSlug, name);
680
+ }
681
+
682
+ if (current === undefined || current.id === undefined) {
683
+ return yield* new PostgresNotCreated({ resourceName: name, orgSlug });
684
+ }
685
+ // `current` is reassigned below; the id is stable across the waits.
686
+ const clusterId = current.id;
687
+
688
+ if (current.status !== "ready") {
689
+ current =
690
+ (yield* waitUntilReady(clusterId)) ?? (yield* getLiveCluster(clusterId)) ?? current;
691
+ }
692
+
693
+ if (current.status === "error") {
694
+ return yield* new PostgresCreateFailed({
695
+ clusterId,
696
+ status: current.status,
697
+ });
698
+ }
699
+
700
+ const observed = yield* waitForCredentials(clusterId);
701
+ const cluster = observed?.data ?? current;
702
+ const credentials = observed?.credentials;
703
+ const migrationUri = directUri(cluster, credentials) ?? credentialsUri(credentials);
704
+
705
+ const migrationsInput = migrationsInputOf(props);
706
+ if (migrationsInput && (migrationUri === undefined || migrationUri.length === 0)) {
707
+ return yield* new PostgresCredentialsMissing({ clusterId });
708
+ }
709
+ const connectionUri = migrationUri !== undefined ? Redacted.make(migrationUri) : undefined;
710
+ const migrations =
711
+ migrationsInput && connectionUri !== undefined
712
+ ? yield* runPgMigrations({
713
+ connectionUri,
714
+ input: migrationsInput,
715
+ stamped: stampedOf(output),
716
+ })
717
+ : undefined;
718
+ const importHashes =
719
+ props.importFiles?.length && connectionUri !== undefined
720
+ ? yield* runImports(
721
+ connectionUri,
722
+ props.importFiles,
723
+ yield* rootDir,
724
+ output?.importHashes ?? {},
725
+ )
726
+ : (output?.importHashes ?? {});
727
+
728
+ return {
729
+ ...toAttrs(cluster, { name, orgSlug, ...output }, credentials),
730
+ ...migrationsAttrs({
731
+ input: migrationsInput,
732
+ run: migrations,
733
+ output,
734
+ }),
735
+ importHashes,
736
+ };
737
+ }),
738
+
739
+ delete: Effect.fn(function* ({ output }) {
740
+ const clusterId = output.clusterId;
741
+ if (clusterId.length === 0) return;
742
+ const orgSlug = output.orgSlug ?? (yield* resolveOrgSlug());
743
+ const observed = yield* getClusterResponse(clusterId);
744
+ const apps = observed?.data?.attached_apps ?? [];
745
+ yield* Effect.forEach(
746
+ apps,
747
+ (app) => {
748
+ const appName = app.name;
749
+ if (appName === undefined || appName.length === 0) {
750
+ return Effect.void;
751
+ }
752
+ return Effect.gen(function* () {
753
+ yield* mpg
754
+ .deleteAttachment({ id: clusterId, app_name: appName })
755
+ .pipe(Effect.catchTag("NotFound", () => Effect.void));
756
+ yield* machines
757
+ .deleteSecret({
758
+ app_name: appName,
759
+ secret_name: DATABASE_URL_SECRET,
760
+ })
761
+ .pipe(Effect.catchTag("NotFound", () => Effect.void));
762
+ yield* machines
763
+ .deleteSecret({
764
+ app_name: appName,
765
+ secret_name: DIRECT_DATABASE_URL_SECRET,
766
+ })
767
+ .pipe(Effect.catchTag("NotFound", () => Effect.void));
768
+ });
769
+ },
770
+ { concurrency: 4 },
771
+ );
772
+ yield* mpg
773
+ .destroyCluster({ org_slug: orgSlug, id: clusterId })
774
+ .pipe(Effect.catchTag("NotFound", () => Effect.void));
775
+ yield* waitUntilGone(clusterId);
776
+ }),
777
+ });