@alchemy.run/fly 0.0.0 → 2.0.0-beta.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +57 -4
- package/lib/App.d.ts +230 -0
- package/lib/App.d.ts.map +1 -0
- package/lib/App.js +340 -0
- package/lib/App.js.map +1 -0
- package/lib/AuthProvider.d.ts +22 -0
- package/lib/AuthProvider.d.ts.map +1 -0
- package/lib/AuthProvider.js +48 -0
- package/lib/AuthProvider.js.map +1 -0
- package/lib/BindService.d.ts +159 -0
- package/lib/BindService.d.ts.map +1 -0
- package/lib/BindService.js +222 -0
- package/lib/BindService.js.map +1 -0
- package/lib/Bootstrap.d.ts +8 -0
- package/lib/Bootstrap.d.ts.map +1 -0
- package/lib/Bootstrap.js +41 -0
- package/lib/Bootstrap.js.map +1 -0
- package/lib/Bucket.d.ts +278 -0
- package/lib/Bucket.d.ts.map +1 -0
- package/lib/Bucket.js +658 -0
- package/lib/Bucket.js.map +1 -0
- package/lib/BucketBinding.d.ts +33 -0
- package/lib/BucketBinding.d.ts.map +1 -0
- package/lib/BucketBinding.js +70 -0
- package/lib/BucketBinding.js.map +1 -0
- package/lib/Catalog.d.ts +28 -0
- package/lib/Catalog.d.ts.map +1 -0
- package/lib/Catalog.js +31 -0
- package/lib/Catalog.js.map +1 -0
- package/lib/Certificate.d.ts +189 -0
- package/lib/Certificate.d.ts.map +1 -0
- package/lib/Certificate.js +380 -0
- package/lib/Certificate.js.map +1 -0
- package/lib/Checkpoint.d.ts +55 -0
- package/lib/Checkpoint.d.ts.map +1 -0
- package/lib/Checkpoint.js +3 -0
- package/lib/Checkpoint.js.map +1 -0
- package/lib/CheckpointHttp.d.ts +22 -0
- package/lib/CheckpointHttp.d.ts.map +1 -0
- package/lib/CheckpointHttp.js +53 -0
- package/lib/CheckpointHttp.js.map +1 -0
- package/lib/ConnectPostgres.d.ts +58 -0
- package/lib/ConnectPostgres.d.ts.map +1 -0
- package/lib/ConnectPostgres.js +13 -0
- package/lib/ConnectPostgres.js.map +1 -0
- package/lib/ConnectPostgresHttp.d.ts +26 -0
- package/lib/ConnectPostgresHttp.d.ts.map +1 -0
- package/lib/ConnectPostgresHttp.js +57 -0
- package/lib/ConnectPostgresHttp.js.map +1 -0
- package/lib/Contributions.d.ts +7 -0
- package/lib/Contributions.d.ts.map +1 -0
- package/lib/Contributions.js +6 -0
- package/lib/Contributions.js.map +1 -0
- package/lib/Credentials.d.ts +33 -0
- package/lib/Credentials.d.ts.map +1 -0
- package/lib/Credentials.js +59 -0
- package/lib/Credentials.js.map +1 -0
- package/lib/Decrypt.d.ts +52 -0
- package/lib/Decrypt.d.ts.map +1 -0
- package/lib/Decrypt.js +3 -0
- package/lib/Decrypt.js.map +1 -0
- package/lib/DecryptHttp.d.ts +22 -0
- package/lib/DecryptHttp.d.ts.map +1 -0
- package/lib/DecryptHttp.js +43 -0
- package/lib/DecryptHttp.js.map +1 -0
- package/lib/DeleteObject.d.ts +29 -0
- package/lib/DeleteObject.d.ts.map +1 -0
- package/lib/DeleteObject.js +3 -0
- package/lib/DeleteObject.js.map +1 -0
- package/lib/DeleteObjectHttp.d.ts +12 -0
- package/lib/DeleteObjectHttp.d.ts.map +1 -0
- package/lib/DeleteObjectHttp.js +17 -0
- package/lib/DeleteObjectHttp.js.map +1 -0
- package/lib/Deployment.d.ts +51 -0
- package/lib/Deployment.d.ts.map +1 -0
- package/lib/Deployment.js +62 -0
- package/lib/Deployment.js.map +1 -0
- package/lib/DeploymentImages.d.ts +18 -0
- package/lib/DeploymentImages.d.ts.map +1 -0
- package/lib/DeploymentImages.js +61 -0
- package/lib/DeploymentImages.js.map +1 -0
- package/lib/DeploymentState.d.ts +17 -0
- package/lib/DeploymentState.d.ts.map +1 -0
- package/lib/DeploymentState.js +87 -0
- package/lib/DeploymentState.js.map +1 -0
- package/lib/Encrypt.d.ts +50 -0
- package/lib/Encrypt.d.ts.map +1 -0
- package/lib/Encrypt.js +3 -0
- package/lib/Encrypt.js.map +1 -0
- package/lib/EncryptHttp.d.ts +22 -0
- package/lib/EncryptHttp.d.ts.map +1 -0
- package/lib/EncryptHttp.js +39 -0
- package/lib/EncryptHttp.js.map +1 -0
- package/lib/Environment.d.ts +45 -0
- package/lib/Environment.d.ts.map +1 -0
- package/lib/Environment.js +43 -0
- package/lib/Environment.js.map +1 -0
- package/lib/Errors.d.ts +18 -0
- package/lib/Errors.d.ts.map +1 -0
- package/lib/Errors.js +13 -0
- package/lib/Errors.js.map +1 -0
- package/lib/Exec.d.ts +41 -0
- package/lib/Exec.d.ts.map +1 -0
- package/lib/Exec.js +3 -0
- package/lib/Exec.js.map +1 -0
- package/lib/ExecHttp.d.ts +22 -0
- package/lib/ExecHttp.d.ts.map +1 -0
- package/lib/ExecHttp.js +39 -0
- package/lib/ExecHttp.js.map +1 -0
- package/lib/GetObject.d.ts +34 -0
- package/lib/GetObject.d.ts.map +1 -0
- package/lib/GetObject.js +3 -0
- package/lib/GetObject.js.map +1 -0
- package/lib/GetObjectHttp.d.ts +12 -0
- package/lib/GetObjectHttp.d.ts.map +1 -0
- package/lib/GetObjectHttp.js +17 -0
- package/lib/GetObjectHttp.js.map +1 -0
- package/lib/GetSecret.d.ts +44 -0
- package/lib/GetSecret.d.ts.map +1 -0
- package/lib/GetSecret.js +3 -0
- package/lib/GetSecret.js.map +1 -0
- package/lib/GetSecretHttp.d.ts +22 -0
- package/lib/GetSecretHttp.d.ts.map +1 -0
- package/lib/GetSecretHttp.js +50 -0
- package/lib/GetSecretHttp.js.map +1 -0
- package/lib/HeadObject.d.ts +29 -0
- package/lib/HeadObject.d.ts.map +1 -0
- package/lib/HeadObject.js +3 -0
- package/lib/HeadObject.js.map +1 -0
- package/lib/HeadObjectHttp.d.ts +12 -0
- package/lib/HeadObjectHttp.d.ts.map +1 -0
- package/lib/HeadObjectHttp.js +17 -0
- package/lib/HeadObjectHttp.js.map +1 -0
- package/lib/IpAssignment.d.ts +258 -0
- package/lib/IpAssignment.d.ts.map +1 -0
- package/lib/IpAssignment.js +376 -0
- package/lib/IpAssignment.js.map +1 -0
- package/lib/ListObjectsV2.d.ts +29 -0
- package/lib/ListObjectsV2.d.ts.map +1 -0
- package/lib/ListObjectsV2.js +3 -0
- package/lib/ListObjectsV2.js.map +1 -0
- package/lib/ListObjectsV2Http.d.ts +12 -0
- package/lib/ListObjectsV2Http.d.ts.map +1 -0
- package/lib/ListObjectsV2Http.js +17 -0
- package/lib/ListObjectsV2Http.js.map +1 -0
- package/lib/ListSecrets.d.ts +53 -0
- package/lib/ListSecrets.d.ts.map +1 -0
- package/lib/ListSecrets.js +3 -0
- package/lib/ListSecrets.js.map +1 -0
- package/lib/ListSecretsHttp.d.ts +22 -0
- package/lib/ListSecretsHttp.d.ts.map +1 -0
- package/lib/ListSecretsHttp.js +35 -0
- package/lib/ListSecretsHttp.js.map +1 -0
- package/lib/Machine.d.ts +802 -0
- package/lib/Machine.d.ts.map +1 -0
- package/lib/Machine.js +773 -0
- package/lib/Machine.js.map +1 -0
- package/lib/MachineContainers.d.ts +44 -0
- package/lib/MachineContainers.d.ts.map +1 -0
- package/lib/MachineContainers.js +115 -0
- package/lib/MachineContainers.js.map +1 -0
- package/lib/Metadata.d.ts +109 -0
- package/lib/Metadata.d.ts.map +1 -0
- package/lib/Metadata.js +159 -0
- package/lib/Metadata.js.map +1 -0
- package/lib/MountVolume.d.ts +295 -0
- package/lib/MountVolume.d.ts.map +1 -0
- package/lib/MountVolume.js +20 -0
- package/lib/MountVolume.js.map +1 -0
- package/lib/Postgres.d.ts +298 -0
- package/lib/Postgres.d.ts.map +1 -0
- package/lib/Postgres.js +508 -0
- package/lib/Postgres.js.map +1 -0
- package/lib/PostgresMigrations.d.ts +35 -0
- package/lib/PostgresMigrations.d.ts.map +1 -0
- package/lib/PostgresMigrations.js +110 -0
- package/lib/PostgresMigrations.js.map +1 -0
- package/lib/Providers.d.ts +38 -0
- package/lib/Providers.d.ts.map +1 -0
- package/lib/Providers.js +95 -0
- package/lib/Providers.js.map +1 -0
- package/lib/PutObject.d.ts +35 -0
- package/lib/PutObject.d.ts.map +1 -0
- package/lib/PutObject.js +3 -0
- package/lib/PutObject.js.map +1 -0
- package/lib/PutObjectHttp.d.ts +12 -0
- package/lib/PutObjectHttp.d.ts.map +1 -0
- package/lib/PutObjectHttp.js +17 -0
- package/lib/PutObjectHttp.js.map +1 -0
- package/lib/ReadRedis.d.ts +26 -0
- package/lib/ReadRedis.d.ts.map +1 -0
- package/lib/ReadRedis.js +3 -0
- package/lib/ReadRedis.js.map +1 -0
- package/lib/ReadRedisHttp.d.ts +11 -0
- package/lib/ReadRedisHttp.d.ts.map +1 -0
- package/lib/ReadRedisHttp.js +15 -0
- package/lib/ReadRedisHttp.js.map +1 -0
- package/lib/ReadWriteRedis.d.ts +29 -0
- package/lib/ReadWriteRedis.d.ts.map +1 -0
- package/lib/ReadWriteRedis.js +3 -0
- package/lib/ReadWriteRedis.js.map +1 -0
- package/lib/ReadWriteRedisHttp.d.ts +11 -0
- package/lib/ReadWriteRedisHttp.d.ts.map +1 -0
- package/lib/ReadWriteRedisHttp.js +15 -0
- package/lib/ReadWriteRedisHttp.js.map +1 -0
- package/lib/Redis.d.ts +252 -0
- package/lib/Redis.d.ts.map +1 -0
- package/lib/Redis.js +608 -0
- package/lib/Redis.js.map +1 -0
- package/lib/RedisBinding.d.ts +7 -0
- package/lib/RedisBinding.d.ts.map +1 -0
- package/lib/RedisBinding.js +53 -0
- package/lib/RedisBinding.js.map +1 -0
- package/lib/RedisHttp.d.ts +8 -0
- package/lib/RedisHttp.d.ts.map +1 -0
- package/lib/RedisHttp.js +8 -0
- package/lib/RedisHttp.js.map +1 -0
- package/lib/Region.d.ts +16 -0
- package/lib/Region.d.ts.map +1 -0
- package/lib/Region.js +13 -0
- package/lib/Region.js.map +1 -0
- package/lib/Secret.d.ts +190 -0
- package/lib/Secret.d.ts.map +1 -0
- package/lib/Secret.js +310 -0
- package/lib/Secret.js.map +1 -0
- package/lib/SecretHttp.d.ts +54 -0
- package/lib/SecretHttp.d.ts.map +1 -0
- package/lib/SecretHttp.js +66 -0
- package/lib/SecretHttp.js.map +1 -0
- package/lib/SecretKey.d.ts +164 -0
- package/lib/SecretKey.d.ts.map +1 -0
- package/lib/SecretKey.js +277 -0
- package/lib/SecretKey.js.map +1 -0
- package/lib/SecretKeyHttp.d.ts +14 -0
- package/lib/SecretKeyHttp.d.ts.map +1 -0
- package/lib/SecretKeyHttp.js +5 -0
- package/lib/SecretKeyHttp.js.map +1 -0
- package/lib/Service.d.ts +1022 -0
- package/lib/Service.d.ts.map +1 -0
- package/lib/Service.js +1397 -0
- package/lib/Service.js.map +1 -0
- package/lib/Sign.d.ts +36 -0
- package/lib/Sign.d.ts.map +1 -0
- package/lib/Sign.js +3 -0
- package/lib/Sign.js.map +1 -0
- package/lib/SignHttp.d.ts +22 -0
- package/lib/SignHttp.d.ts.map +1 -0
- package/lib/SignHttp.js +36 -0
- package/lib/SignHttp.js.map +1 -0
- package/lib/Sprite.d.ts +283 -0
- package/lib/Sprite.d.ts.map +1 -0
- package/lib/Sprite.js +469 -0
- package/lib/Sprite.js.map +1 -0
- package/lib/SpriteHttp.d.ts +25 -0
- package/lib/SpriteHttp.d.ts.map +1 -0
- package/lib/SpriteHttp.js +33 -0
- package/lib/SpriteHttp.js.map +1 -0
- package/lib/Verify.d.ts +37 -0
- package/lib/Verify.d.ts.map +1 -0
- package/lib/Verify.js +3 -0
- package/lib/Verify.js.map +1 -0
- package/lib/VerifyHttp.d.ts +22 -0
- package/lib/VerifyHttp.d.ts.map +1 -0
- package/lib/VerifyHttp.js +38 -0
- package/lib/VerifyHttp.js.map +1 -0
- package/lib/Volume.d.ts +53 -0
- package/lib/Volume.d.ts.map +1 -0
- package/lib/Volume.js +188 -0
- package/lib/Volume.js.map +1 -0
- package/lib/VolumeSnapshot.d.ts +135 -0
- package/lib/VolumeSnapshot.d.ts.map +1 -0
- package/lib/VolumeSnapshot.js +213 -0
- package/lib/VolumeSnapshot.js.map +1 -0
- package/lib/Website/AssetDeployment.d.ts +43 -0
- package/lib/Website/AssetDeployment.d.ts.map +1 -0
- package/lib/Website/AssetDeployment.js +162 -0
- package/lib/Website/AssetDeployment.js.map +1 -0
- package/lib/Website/Astro.d.ts +87 -0
- package/lib/Website/Astro.d.ts.map +1 -0
- package/lib/Website/Astro.js +55 -0
- package/lib/Website/Astro.js.map +1 -0
- package/lib/Website/Foldkit.d.ts +52 -0
- package/lib/Website/Foldkit.d.ts.map +1 -0
- package/lib/Website/Foldkit.js +45 -0
- package/lib/Website/Foldkit.js.map +1 -0
- package/lib/Website/FrameworkSite.d.ts +175 -0
- package/lib/Website/FrameworkSite.d.ts.map +1 -0
- package/lib/Website/FrameworkSite.js +162 -0
- package/lib/Website/FrameworkSite.js.map +1 -0
- package/lib/Website/Nextjs.d.ts +54 -0
- package/lib/Website/Nextjs.d.ts.map +1 -0
- package/lib/Website/Nextjs.js +46 -0
- package/lib/Website/Nextjs.js.map +1 -0
- package/lib/Website/Nuxt.d.ts +51 -0
- package/lib/Website/Nuxt.d.ts.map +1 -0
- package/lib/Website/Nuxt.js +36 -0
- package/lib/Website/Nuxt.js.map +1 -0
- package/lib/Website/Octane.d.ts +49 -0
- package/lib/Website/Octane.d.ts.map +1 -0
- package/lib/Website/Octane.js +39 -0
- package/lib/Website/Octane.js.map +1 -0
- package/lib/Website/ReactRouter.d.ts +80 -0
- package/lib/Website/ReactRouter.d.ts.map +1 -0
- package/lib/Website/ReactRouter.js +70 -0
- package/lib/Website/ReactRouter.js.map +1 -0
- package/lib/Website/SolidStart.d.ts +93 -0
- package/lib/Website/SolidStart.d.ts.map +1 -0
- package/lib/Website/SolidStart.js +71 -0
- package/lib/Website/SolidStart.js.map +1 -0
- package/lib/Website/StaticSite.d.ts +155 -0
- package/lib/Website/StaticSite.d.ts.map +1 -0
- package/lib/Website/StaticSite.js +168 -0
- package/lib/Website/StaticSite.js.map +1 -0
- package/lib/Website/SvelteKit.d.ts +52 -0
- package/lib/Website/SvelteKit.d.ts.map +1 -0
- package/lib/Website/SvelteKit.js +37 -0
- package/lib/Website/SvelteKit.js.map +1 -0
- package/lib/Website/TanStackStart.d.ts +76 -0
- package/lib/Website/TanStackStart.d.ts.map +1 -0
- package/lib/Website/TanStackStart.js +66 -0
- package/lib/Website/TanStackStart.js.map +1 -0
- package/lib/Website/Vinext.d.ts +73 -0
- package/lib/Website/Vinext.d.ts.map +1 -0
- package/lib/Website/Vinext.js +67 -0
- package/lib/Website/Vinext.js.map +1 -0
- package/lib/Website/Vite.d.ts +103 -0
- package/lib/Website/Vite.d.ts.map +1 -0
- package/lib/Website/Vite.js +91 -0
- package/lib/Website/Vite.js.map +1 -0
- package/lib/Website/Vocs.d.ts +52 -0
- package/lib/Website/Vocs.d.ts.map +1 -0
- package/lib/Website/Vocs.js +38 -0
- package/lib/Website/Vocs.js.map +1 -0
- package/lib/Website/Waku.d.ts +64 -0
- package/lib/Website/Waku.d.ts.map +1 -0
- package/lib/Website/Waku.js +39 -0
- package/lib/Website/Waku.js.map +1 -0
- package/lib/Website/index.d.ts +17 -0
- package/lib/Website/index.d.ts.map +1 -0
- package/lib/Website/index.js +17 -0
- package/lib/Website/index.js.map +1 -0
- package/lib/WriteCertificates.d.ts +63 -0
- package/lib/WriteCertificates.d.ts.map +1 -0
- package/lib/WriteCertificates.js +3 -0
- package/lib/WriteCertificates.js.map +1 -0
- package/lib/WriteCertificatesHttp.d.ts +25 -0
- package/lib/WriteCertificatesHttp.d.ts.map +1 -0
- package/lib/WriteCertificatesHttp.js +67 -0
- package/lib/WriteCertificatesHttp.js.map +1 -0
- package/lib/WriteRedis.d.ts +26 -0
- package/lib/WriteRedis.d.ts.map +1 -0
- package/lib/WriteRedis.js +3 -0
- package/lib/WriteRedis.js.map +1 -0
- package/lib/WriteRedisHttp.d.ts +11 -0
- package/lib/WriteRedisHttp.d.ts.map +1 -0
- package/lib/WriteRedisHttp.js +15 -0
- package/lib/WriteRedisHttp.js.map +1 -0
- package/lib/WriteSecret.d.ts +68 -0
- package/lib/WriteSecret.d.ts.map +1 -0
- package/lib/WriteSecret.js +4 -0
- package/lib/WriteSecret.js.map +1 -0
- package/lib/WriteSecretHttp.d.ts +26 -0
- package/lib/WriteSecretHttp.d.ts.map +1 -0
- package/lib/WriteSecretHttp.js +54 -0
- package/lib/WriteSecretHttp.js.map +1 -0
- package/lib/bluegreen.d.ts +36 -0
- package/lib/bluegreen.d.ts.map +1 -0
- package/lib/bluegreen.js +458 -0
- package/lib/bluegreen.js.map +1 -0
- package/lib/hosted.d.ts +172 -0
- package/lib/hosted.d.ts.map +1 -0
- package/lib/hosted.js +458 -0
- package/lib/hosted.js.map +1 -0
- package/lib/index.d.ts +65 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +63 -0
- package/lib/index.js.map +1 -0
- package/lib/internal/RemoteBuilder.d.ts +28 -0
- package/lib/internal/RemoteBuilder.d.ts.map +1 -0
- package/lib/internal/RemoteBuilder.js +145 -0
- package/lib/internal/RemoteBuilder.js.map +1 -0
- package/lib/leases.d.ts +53 -0
- package/lib/leases.d.ts.map +1 -0
- package/lib/leases.js +279 -0
- package/lib/leases.js.map +1 -0
- package/lib/ports.d.ts +51 -0
- package/lib/ports.d.ts.map +1 -0
- package/lib/ports.js +123 -0
- package/lib/ports.js.map +1 -0
- package/lib/replicas.d.ts +270 -0
- package/lib/replicas.d.ts.map +1 -0
- package/lib/replicas.js +969 -0
- package/lib/replicas.js.map +1 -0
- package/lib/rpc.d.ts +35 -0
- package/lib/rpc.d.ts.map +1 -0
- package/lib/rpc.js +113 -0
- package/lib/rpc.js.map +1 -0
- package/package.json +83 -3
- package/src/App.ts +516 -0
- package/src/AuthProvider.ts +68 -0
- package/src/BindService.ts +304 -0
- package/src/Bootstrap.ts +66 -0
- package/src/Bucket.ts +916 -0
- package/src/BucketBinding.ts +128 -0
- package/src/Catalog.ts +43 -0
- package/src/Certificate.ts +548 -0
- package/src/Checkpoint.ts +69 -0
- package/src/CheckpointHttp.ts +66 -0
- package/src/ConnectPostgres.ts +68 -0
- package/src/ConnectPostgresHttp.ts +77 -0
- package/src/Contributions.ts +9 -0
- package/src/Credentials.ts +102 -0
- package/src/Decrypt.ts +62 -0
- package/src/DecryptHttp.ts +52 -0
- package/src/DeleteObject.ts +43 -0
- package/src/DeleteObjectHttp.ts +20 -0
- package/src/Deployment.ts +121 -0
- package/src/DeploymentImages.ts +84 -0
- package/src/DeploymentState.ts +104 -0
- package/src/Encrypt.ts +60 -0
- package/src/EncryptHttp.ts +48 -0
- package/src/Environment.ts +81 -0
- package/src/Errors.ts +14 -0
- package/src/Exec.ts +50 -0
- package/src/ExecHttp.ts +47 -0
- package/src/GetObject.ts +48 -0
- package/src/GetObjectHttp.ts +20 -0
- package/src/GetSecret.ts +48 -0
- package/src/GetSecretHttp.ts +60 -0
- package/src/HeadObject.ts +43 -0
- package/src/HeadObjectHttp.ts +20 -0
- package/src/IpAssignment.ts +522 -0
- package/src/ListObjectsV2.ts +43 -0
- package/src/ListObjectsV2Http.ts +20 -0
- package/src/ListSecrets.ts +57 -0
- package/src/ListSecretsHttp.ts +43 -0
- package/src/Machine.ts +1268 -0
- package/src/MachineContainers.ts +152 -0
- package/src/Metadata.ts +195 -0
- package/src/MountVolume.ts +315 -0
- package/src/Postgres.ts +777 -0
- package/src/PostgresMigrations.ts +153 -0
- package/src/Providers.ts +155 -0
- package/src/PutObject.ts +49 -0
- package/src/PutObjectHttp.ts +20 -0
- package/src/ReadRedis.ts +31 -0
- package/src/ReadRedisHttp.ts +18 -0
- package/src/ReadWriteRedis.ts +33 -0
- package/src/ReadWriteRedisHttp.ts +18 -0
- package/src/Redis.ts +820 -0
- package/src/RedisBinding.ts +64 -0
- package/src/RedisHttp.ts +11 -0
- package/src/Region.ts +44 -0
- package/src/Secret.ts +405 -0
- package/src/SecretHttp.ts +149 -0
- package/src/SecretKey.ts +389 -0
- package/src/SecretKeyHttp.ts +23 -0
- package/src/Service.ts +1934 -0
- package/src/Sign.ts +46 -0
- package/src/SignHttp.ts +44 -0
- package/src/Sprite.ts +671 -0
- package/src/SpriteHttp.ts +50 -0
- package/src/Verify.ts +47 -0
- package/src/VerifyHttp.ts +46 -0
- package/src/Volume.ts +264 -0
- package/src/VolumeSnapshot.ts +321 -0
- package/src/Website/AssetDeployment.ts +294 -0
- package/src/Website/Astro.ts +87 -0
- package/src/Website/Foldkit.ts +54 -0
- package/src/Website/FrameworkSite.ts +363 -0
- package/src/Website/Nextjs.ts +50 -0
- package/src/Website/Nuxt.ts +48 -0
- package/src/Website/Octane.ts +44 -0
- package/src/Website/ReactRouter.ts +76 -0
- package/src/Website/SolidStart.ts +90 -0
- package/src/Website/StaticSite.ts +275 -0
- package/src/Website/SvelteKit.ts +49 -0
- package/src/Website/TanStackStart.ts +72 -0
- package/src/Website/Vinext.ts +79 -0
- package/src/Website/Vite.ts +112 -0
- package/src/Website/Vocs.ts +50 -0
- package/src/Website/Waku.ts +65 -0
- package/src/Website/index.ts +16 -0
- package/src/WriteCertificates.ts +90 -0
- package/src/WriteCertificatesHttp.ts +93 -0
- package/src/WriteRedis.ts +31 -0
- package/src/WriteRedisHttp.ts +18 -0
- package/src/WriteSecret.ts +86 -0
- package/src/WriteSecretHttp.ts +71 -0
- package/src/bluegreen.ts +708 -0
- package/src/globals.d.ts +2 -0
- package/src/hosted.ts +668 -0
- package/src/index.ts +64 -0
- package/src/internal/RemoteBuilder.ts +224 -0
- package/src/leases.ts +437 -0
- package/src/ports.ts +177 -0
- package/src/replicas.ts +1480 -0
- package/src/rpc.ts +136 -0
package/src/Machine.ts
ADDED
|
@@ -0,0 +1,1268 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FlyMachineConfig,
|
|
3
|
+
FlyMachineGuest,
|
|
4
|
+
FlyMachineInit,
|
|
5
|
+
FlyMachineMount,
|
|
6
|
+
FlyMachineRestart,
|
|
7
|
+
FlyMachineService,
|
|
8
|
+
Machine as FlyMachine,
|
|
9
|
+
} from "@distilled.cloud/fly-io/machines";
|
|
10
|
+
import { deepEqual, isResolved } from "alchemy/Diff";
|
|
11
|
+
import type { Input } from "alchemy/Input";
|
|
12
|
+
import * as Provider from "alchemy/Provider";
|
|
13
|
+
import { Resource, type ResourceBinding } from "alchemy/Resource";
|
|
14
|
+
import * as Data from "effect/Data";
|
|
15
|
+
import * as Effect from "effect/Effect";
|
|
16
|
+
import { App } from "./App.ts";
|
|
17
|
+
import {
|
|
18
|
+
deploymentPolicy,
|
|
19
|
+
validateDeployment,
|
|
20
|
+
type MachineDeploy,
|
|
21
|
+
type MachineShutdown,
|
|
22
|
+
type MachineCheck,
|
|
23
|
+
} from "./Deployment.ts";
|
|
24
|
+
import { toEnvRecord } from "./hosted.ts";
|
|
25
|
+
import {
|
|
26
|
+
sameContainerWorkload,
|
|
27
|
+
toFlyContainers,
|
|
28
|
+
validateMachineContainers,
|
|
29
|
+
} from "./MachineContainers.ts";
|
|
30
|
+
import { createFlyResourceName, diffMachineMetadata, sanitizeFlyAppName } from "./Metadata.ts";
|
|
31
|
+
import type { DiskSpec, MountedDisk, ServiceBinding } from "./MountVolume.ts";
|
|
32
|
+
import type { Providers } from "./Providers.ts";
|
|
33
|
+
import {
|
|
34
|
+
deleteReplicaSet,
|
|
35
|
+
listReplicaSets,
|
|
36
|
+
observeReplicaSet,
|
|
37
|
+
reconcileReplicas,
|
|
38
|
+
resolveCount,
|
|
39
|
+
sameServices,
|
|
40
|
+
toFlyService,
|
|
41
|
+
volumeIdsOf,
|
|
42
|
+
type Replica,
|
|
43
|
+
type ReplicaSet,
|
|
44
|
+
} from "./replicas.ts";
|
|
45
|
+
|
|
46
|
+
export type { Replica };
|
|
47
|
+
|
|
48
|
+
const DEFAULT_REGION = "iad";
|
|
49
|
+
const DEFAULT_CPU_KIND = "shared";
|
|
50
|
+
const DEFAULT_CPUS = 1;
|
|
51
|
+
const DEFAULT_MEMORY_MB = 256;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* A resource-valued prop: the resource itself, or an Effect that produces
|
|
55
|
+
* it (so `yield* App(...)` and `App(...)` both type-check).
|
|
56
|
+
*/
|
|
57
|
+
type Ref<T> = T | Effect.Effect<T, never, Providers>;
|
|
58
|
+
|
|
59
|
+
export interface MachineGuest {
|
|
60
|
+
/**
|
|
61
|
+
* CPU kind (`shared`, `performance`, `shared-cpu-1x`, …).
|
|
62
|
+
*
|
|
63
|
+
* @default "shared"
|
|
64
|
+
*/
|
|
65
|
+
cpuKind?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Number of CPUs.
|
|
68
|
+
*
|
|
69
|
+
* @default 1
|
|
70
|
+
*/
|
|
71
|
+
cpus?: number;
|
|
72
|
+
/**
|
|
73
|
+
* Memory in MB.
|
|
74
|
+
*
|
|
75
|
+
* @default 256
|
|
76
|
+
*/
|
|
77
|
+
memoryMb?: number;
|
|
78
|
+
/** GPU kind, if this Machine should have a GPU. */
|
|
79
|
+
gpuKind?: string;
|
|
80
|
+
/** Number of GPUs. */
|
|
81
|
+
gpus?: number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface MachineInit {
|
|
85
|
+
/** Process command. */
|
|
86
|
+
cmd?: string[];
|
|
87
|
+
/** Container entrypoint. */
|
|
88
|
+
entrypoint?: string[];
|
|
89
|
+
/** Exec form override. */
|
|
90
|
+
exec?: string[];
|
|
91
|
+
/** Swap size in MB. */
|
|
92
|
+
swapSizeMb?: number;
|
|
93
|
+
/** Allocate a TTY. */
|
|
94
|
+
tty?: boolean;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface MachineRestart {
|
|
98
|
+
/**
|
|
99
|
+
* Restart policy (`no`, `always`, `on-failure`, `spot-price`).
|
|
100
|
+
*/
|
|
101
|
+
policy?: "no" | "always" | "on-failure" | "spot-price";
|
|
102
|
+
/** Max restarts when `policy` is `on-failure`. */
|
|
103
|
+
maxRetries?: number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface MachinePort {
|
|
107
|
+
/** Published proxy port. */
|
|
108
|
+
port?: number;
|
|
109
|
+
/** Fly handlers (`http`, `tls`, `pg_tls`, …). */
|
|
110
|
+
handlers?: string[];
|
|
111
|
+
/** Redirect HTTP to HTTPS on this port. */
|
|
112
|
+
forceHttps?: boolean;
|
|
113
|
+
/** Inclusive start of a published port range. */
|
|
114
|
+
startPort?: number;
|
|
115
|
+
/** Inclusive end of a published port range. */
|
|
116
|
+
endPort?: number;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** A health check attached to a Fly service. */
|
|
120
|
+
export interface MachineServiceCheck {
|
|
121
|
+
/** Check type. HTTP checks send a request; TCP checks open a connection. */
|
|
122
|
+
type: "http" | "tcp";
|
|
123
|
+
/** Port to check. Usually the service's {@link MachineService.internalPort}. */
|
|
124
|
+
port?: number;
|
|
125
|
+
/**
|
|
126
|
+
* Time between checks, such as `"15s"`.
|
|
127
|
+
* Fly caps service checks at `"60s"`; this cap does not apply to named Machine checks.
|
|
128
|
+
*/
|
|
129
|
+
interval?: string;
|
|
130
|
+
/** Maximum time for a check, such as `"2s"`. */
|
|
131
|
+
timeout?: string;
|
|
132
|
+
/** Delay after the Machine starts before checks begin, such as `"30s"`. */
|
|
133
|
+
gracePeriod?: string;
|
|
134
|
+
/** HTTP method for an `http` check. */
|
|
135
|
+
method?: string;
|
|
136
|
+
/** Request path for an `http` check. */
|
|
137
|
+
path?: string;
|
|
138
|
+
/** Request protocol for an `http` check. */
|
|
139
|
+
protocol?: "http" | "https";
|
|
140
|
+
/** Headers sent by an `http` check. */
|
|
141
|
+
headers?: Array<{
|
|
142
|
+
/** Header name. */
|
|
143
|
+
name: string;
|
|
144
|
+
/** Header values. */
|
|
145
|
+
values: string[];
|
|
146
|
+
}>;
|
|
147
|
+
/** Hostname used to validate the certificate for an HTTPS check. */
|
|
148
|
+
tlsServerName?: string;
|
|
149
|
+
/** Skip certificate verification for an HTTPS check. */
|
|
150
|
+
tlsSkipVerify?: boolean;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface MachineService {
|
|
154
|
+
/**
|
|
155
|
+
* Proxy protocol (`tcp` or `udp`).
|
|
156
|
+
*/
|
|
157
|
+
protocol?: string;
|
|
158
|
+
/** Port the process listens on inside the Machine. */
|
|
159
|
+
internalPort?: number;
|
|
160
|
+
/** Published Fly proxy ports. */
|
|
161
|
+
ports?: MachinePort[];
|
|
162
|
+
/** Start this Machine when a request arrives. */
|
|
163
|
+
autostart?: boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Stop or suspend this Machine when idle.
|
|
166
|
+
*/
|
|
167
|
+
autostop?: "off" | "stop" | "suspend" | boolean;
|
|
168
|
+
/** Minimum Machines to keep running for this service. */
|
|
169
|
+
minMachinesRunning?: number;
|
|
170
|
+
/** Health checks for this service. */
|
|
171
|
+
checks?: MachineServiceCheck[];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export type MachineMount = DiskSpec;
|
|
175
|
+
|
|
176
|
+
/** Startup dependency on another named container in the same Machine. */
|
|
177
|
+
export interface MachineContainerDependency {
|
|
178
|
+
/** Name of another container in this Machine. */
|
|
179
|
+
name: string;
|
|
180
|
+
/** Startup condition Fly waits for. */
|
|
181
|
+
condition?: "started" | "healthy" | "exited_successfully";
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** A native Pilot health check; timing fields are numeric seconds. */
|
|
185
|
+
export interface MachineContainerHealthCheck {
|
|
186
|
+
/** Optional check name, unique within this container. */
|
|
187
|
+
name?: string;
|
|
188
|
+
/** Whether the check gates readiness or liveness. */
|
|
189
|
+
kind?: "readiness" | "liveness";
|
|
190
|
+
/** Seconds between checks. */
|
|
191
|
+
interval?: number;
|
|
192
|
+
/** Seconds before a check times out. */
|
|
193
|
+
timeout?: number;
|
|
194
|
+
/** Seconds after startup before checks begin. */
|
|
195
|
+
gracePeriod?: number;
|
|
196
|
+
/** Consecutive successes required to become healthy. */
|
|
197
|
+
successThreshold?: number;
|
|
198
|
+
/** Consecutive failures required to become unhealthy. */
|
|
199
|
+
failureThreshold?: number;
|
|
200
|
+
/** HTTP probe. Configure exactly one of HTTP, TCP, or exec. */
|
|
201
|
+
http?: {
|
|
202
|
+
/** Container-local port. */
|
|
203
|
+
port: number;
|
|
204
|
+
/** Request path. */
|
|
205
|
+
path?: string;
|
|
206
|
+
/** Request method. */
|
|
207
|
+
method?: string;
|
|
208
|
+
/** Request scheme. */
|
|
209
|
+
scheme?: "http" | "https";
|
|
210
|
+
/** Additional request headers. */
|
|
211
|
+
headers?: Array<{ name: string; values: string[] }>;
|
|
212
|
+
/** Hostname for TLS certificate verification. */
|
|
213
|
+
tlsServerName?: string;
|
|
214
|
+
/** Skip TLS certificate verification. */
|
|
215
|
+
tlsSkipVerify?: boolean;
|
|
216
|
+
};
|
|
217
|
+
/** TCP connection probe. */
|
|
218
|
+
tcp?: { port: number };
|
|
219
|
+
/** Process execution probe. */
|
|
220
|
+
exec?: { command: string[] };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** One named container in a Machine replica. */
|
|
224
|
+
export interface MachineContainer {
|
|
225
|
+
/** Stable name identifying this container within the group. */
|
|
226
|
+
name: string;
|
|
227
|
+
/** Docker image reference. Rolling deployments accept tags or digests. */
|
|
228
|
+
image: string;
|
|
229
|
+
/** Command override. */
|
|
230
|
+
cmd?: string[];
|
|
231
|
+
/** Entrypoint override. */
|
|
232
|
+
entrypoint?: string[];
|
|
233
|
+
/** Per-container environment variables; Fly applies these over Machine env. */
|
|
234
|
+
env?: Record<string, string>;
|
|
235
|
+
/** Other named containers that must reach a startup condition first. */
|
|
236
|
+
dependsOn?: MachineContainerDependency[];
|
|
237
|
+
/** Native Pilot checks for this container. Deployment readiness is configured separately. */
|
|
238
|
+
healthChecks?: MachineContainerHealthCheck[];
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export interface MachinePropsBase {
|
|
242
|
+
/** Deployment strategy and readiness deadline. Defaults to in-place rolling updates. */
|
|
243
|
+
deploy?: MachineDeploy;
|
|
244
|
+
/** Graceful process shutdown. Defaults to SIGTERM / 30 seconds when blue/green is enabled. */
|
|
245
|
+
shutdown?: MachineShutdown;
|
|
246
|
+
/** Named readiness checks for workers without public services. */
|
|
247
|
+
checks?: Record<string, MachineCheck>;
|
|
248
|
+
/**
|
|
249
|
+
* Parent Fly App. Changing it replaces the Machine.
|
|
250
|
+
*/
|
|
251
|
+
app: Ref<App>;
|
|
252
|
+
/**
|
|
253
|
+
* Machine name. Unique per App. If omitted, a unique name is generated
|
|
254
|
+
* from the stack, stage and logical ID. Changing it replaces the Machine.
|
|
255
|
+
* In blue/green mode this is a base for generation-qualified physical names.
|
|
256
|
+
*/
|
|
257
|
+
name?: string;
|
|
258
|
+
/**
|
|
259
|
+
* Region to start the Machine in (`iad`, `ewr`, `ord`, …). Changing it
|
|
260
|
+
* replaces the Machine.
|
|
261
|
+
*
|
|
262
|
+
* @default "iad"
|
|
263
|
+
*/
|
|
264
|
+
region?: string;
|
|
265
|
+
/**
|
|
266
|
+
* Number of Machines to provision, including stopped/suspended idle capacity.
|
|
267
|
+
* Fly's proxy load-balances published `services` across available replicas.
|
|
268
|
+
* Blue/green checks a representative and the required running floor while
|
|
269
|
+
* preserving idle nonrepresentatives. Each replica gets its own Volume
|
|
270
|
+
* from every {@link mounts} group; attached volumes require rolling updates.
|
|
271
|
+
*
|
|
272
|
+
* @default 1
|
|
273
|
+
*/
|
|
274
|
+
count?: number;
|
|
275
|
+
/**
|
|
276
|
+
* Guest size. Defaults to shared-cpu-1x 256 MB.
|
|
277
|
+
*/
|
|
278
|
+
guest?: MachineGuest;
|
|
279
|
+
/**
|
|
280
|
+
* Environment variables. Merged with binding `env`.
|
|
281
|
+
*/
|
|
282
|
+
env?: Record<string, string>;
|
|
283
|
+
/**
|
|
284
|
+
* Fly proxy services (HTTP/TCP ports).
|
|
285
|
+
*/
|
|
286
|
+
services?: MachineService[];
|
|
287
|
+
/**
|
|
288
|
+
* Disks to attach. Each entry is a Fly volume group: `count`
|
|
289
|
+
* independent Volumes, one mounted on each replica. Also collected
|
|
290
|
+
* from `MountVolume` bindings.
|
|
291
|
+
*/
|
|
292
|
+
mounts?: MachineMount[];
|
|
293
|
+
/**
|
|
294
|
+
* User metadata. Alchemy ownership keys (`alchemy.stack` /
|
|
295
|
+
* `alchemy.stage` / `alchemy.id` / `alchemy.type` /
|
|
296
|
+
* `alchemy.replica`) are always merged.
|
|
297
|
+
*/
|
|
298
|
+
metadata?: Record<string, string>;
|
|
299
|
+
/**
|
|
300
|
+
* Destroy the Machine when its main process exits.
|
|
301
|
+
*
|
|
302
|
+
* @default false
|
|
303
|
+
*/
|
|
304
|
+
autoDestroy?: boolean;
|
|
305
|
+
/**
|
|
306
|
+
* Restart policy after the main process exits.
|
|
307
|
+
*/
|
|
308
|
+
restart?: MachineRestart;
|
|
309
|
+
/**
|
|
310
|
+
* Create or update without launching the Machine.
|
|
311
|
+
*
|
|
312
|
+
* @default false
|
|
313
|
+
*/
|
|
314
|
+
skipLaunch?: boolean;
|
|
315
|
+
/**
|
|
316
|
+
* Minimum App-secrets version required by this Machine, not an immutable
|
|
317
|
+
* snapshot. Other writers can advance the shared vault. Secret changes are
|
|
318
|
+
* not automatically watched; change an explicit deployment input or floor
|
|
319
|
+
* when an out-of-band rotation requires reconciliation.
|
|
320
|
+
*/
|
|
321
|
+
minSecretsVersion?: number;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export type MachineProps =
|
|
325
|
+
| (MachinePropsBase & {
|
|
326
|
+
/** Docker image reference. Rolling updates change the existing Machines. */
|
|
327
|
+
image: string;
|
|
328
|
+
containers?: never;
|
|
329
|
+
/** Process init overrides for a single-image Machine. */
|
|
330
|
+
init?: MachineInit;
|
|
331
|
+
})
|
|
332
|
+
| (MachinePropsBase & {
|
|
333
|
+
/** Named containers run together in every Machine replica. */
|
|
334
|
+
containers: MachineContainer[];
|
|
335
|
+
image?: never;
|
|
336
|
+
init?: never;
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
export type MachineImageRef = {
|
|
340
|
+
registry?: string;
|
|
341
|
+
repository?: string;
|
|
342
|
+
tag?: string;
|
|
343
|
+
digest?: string;
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
export type Machine = Resource<
|
|
347
|
+
"Fly.Machine",
|
|
348
|
+
MachineProps,
|
|
349
|
+
{
|
|
350
|
+
/** Whether recovery must finish an interrupted deployment. */
|
|
351
|
+
rolloutPending?: boolean;
|
|
352
|
+
/** Parent Fly App name. */
|
|
353
|
+
appName: string;
|
|
354
|
+
/** Fly Machine id of replica 0. */
|
|
355
|
+
machineId: string;
|
|
356
|
+
/** Fly Machine ids of every replica. */
|
|
357
|
+
machineIds: string[];
|
|
358
|
+
/** Logical base for generation-qualified Machine names. */
|
|
359
|
+
baseName?: string;
|
|
360
|
+
/** Machine name of replica 0 (unique per App). Changes during blue/green deployment. */
|
|
361
|
+
name: string;
|
|
362
|
+
/** Region the Machines are running in. */
|
|
363
|
+
region: string;
|
|
364
|
+
/** Observed state of replica 0 (`created`, `started`, `stopped`, …). */
|
|
365
|
+
state: string;
|
|
366
|
+
/** Fly instance / version id of replica 0, if the API returned one. */
|
|
367
|
+
instanceId: string | undefined;
|
|
368
|
+
/** Internal 6PN address of replica 0. */
|
|
369
|
+
privateIp: string | undefined;
|
|
370
|
+
/** Parsed image reference from Fly. */
|
|
371
|
+
imageRef: MachineImageRef | undefined;
|
|
372
|
+
/** Observed guest size. */
|
|
373
|
+
guest: MachineGuest | undefined;
|
|
374
|
+
/** Number of Machines in the replica set. */
|
|
375
|
+
count: number;
|
|
376
|
+
/** Disks mounted on replica 0. */
|
|
377
|
+
mounts: MountedDisk[];
|
|
378
|
+
/** Every replica in the set. */
|
|
379
|
+
replicas: Replica[];
|
|
380
|
+
},
|
|
381
|
+
ServiceBinding,
|
|
382
|
+
Providers
|
|
383
|
+
>;
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* A Fly.Machine is a Firecracker VM running one image or a named container group.
|
|
387
|
+
*
|
|
388
|
+
* Prefer a {@link Service} when the program is Effect. A Service is effectful, supports bindings,
|
|
389
|
+
* and scales with `count`. Alchemy builds and pushes the image. Use `Fly.Machine` when you already
|
|
390
|
+
* have an image.
|
|
391
|
+
*
|
|
392
|
+
* @see https://fly.io/docs/machines/api/machines-resource/
|
|
393
|
+
*
|
|
394
|
+
* ### Prefer a Service
|
|
395
|
+
* Declare a {@link Service} when you own the program. Alchemy bundles
|
|
396
|
+
* `main`, builds `linux/amd64`, and pushes to `registry.fly.io`.
|
|
397
|
+
*
|
|
398
|
+
* **Example:** Effect HTTP service
|
|
399
|
+
* ```typescript
|
|
400
|
+
* export default class Api extends Fly.Service<Api>()(
|
|
401
|
+
* "Api",
|
|
402
|
+
* { app: Site, main: import.meta.url, region: "iad", count: 3, port: 3000 },
|
|
403
|
+
* Effect.gen(function* () {
|
|
404
|
+
* return {
|
|
405
|
+
* fetch: Effect.succeed(HttpServerResponse.text("hello")),
|
|
406
|
+
* };
|
|
407
|
+
* }),
|
|
408
|
+
* ) {}
|
|
409
|
+
* ```
|
|
410
|
+
*
|
|
411
|
+
* ### Launch a Machine
|
|
412
|
+
* The parent is an {@link App}. Pin a region and an image. Guest
|
|
413
|
+
* defaults to shared-cpu 1× / 256 MB. Rolling updates `image` in place;
|
|
414
|
+
* blue/green prepares replacement Machines.
|
|
415
|
+
*
|
|
416
|
+
* **Example:** Nginx
|
|
417
|
+
* ```typescript
|
|
418
|
+
* const web = yield* Fly.Machine("Web", {
|
|
419
|
+
* app: Site,
|
|
420
|
+
* region: "iad",
|
|
421
|
+
* image: "nginx:alpine",
|
|
422
|
+
* });
|
|
423
|
+
* ```
|
|
424
|
+
*
|
|
425
|
+
* :::caution[Changing `app` replaces the Machine]
|
|
426
|
+
* The new App gets a new Machine. The old one is deleted.
|
|
427
|
+
* :::
|
|
428
|
+
*
|
|
429
|
+
* ### Run named containers
|
|
430
|
+
* Each replica contains the entire group. Container checks and dependencies
|
|
431
|
+
* control Pilot startup; configure Machine or service checks for deployment
|
|
432
|
+
* readiness. Rolling updates can restart the entire group when one image
|
|
433
|
+
* changes. Blue/green requires every named image to use an immutable
|
|
434
|
+
* `repository@sha256:` digest and cannot attach volumes. Alchemy replaces
|
|
435
|
+
* the entire group and applies readiness policy before retiring predecessors.
|
|
436
|
+
*
|
|
437
|
+
* **Example:** API and worker
|
|
438
|
+
* ```typescript
|
|
439
|
+
* const preview = yield* Fly.Machine("Preview", {
|
|
440
|
+
* app: Site,
|
|
441
|
+
* containers: [
|
|
442
|
+
* { name: "api", image: apiImage, healthChecks: [{ http: { port: 3000, path: "/health" } }] },
|
|
443
|
+
* { name: "worker", image: workerImage, dependsOn: [{ name: "api", condition: "healthy" }] },
|
|
444
|
+
* ],
|
|
445
|
+
* });
|
|
446
|
+
* ```
|
|
447
|
+
*
|
|
448
|
+
* ### A stable name
|
|
449
|
+
* Machine names are unique per App. Omit `name` and Alchemy generates
|
|
450
|
+
* one from the stack, stage, and logical ID.
|
|
451
|
+
*
|
|
452
|
+
* **Example:** Explicit name
|
|
453
|
+
* ```typescript
|
|
454
|
+
* const web = yield* Fly.Machine("Web", {
|
|
455
|
+
* app: Site,
|
|
456
|
+
* name: "web",
|
|
457
|
+
* region: "iad",
|
|
458
|
+
* image: "nginx:alpine",
|
|
459
|
+
* });
|
|
460
|
+
* ```
|
|
461
|
+
*
|
|
462
|
+
* :::caution[Changing `name` replaces the Machine]
|
|
463
|
+
* Fly cannot rename a Machine. Alchemy creates the new name, then
|
|
464
|
+
* deletes the old one.
|
|
465
|
+
* :::
|
|
466
|
+
*
|
|
467
|
+
* ### Region
|
|
468
|
+
* Fly Machines live in a region. Default is `iad`. See
|
|
469
|
+
* [Regions](/fly/compute/regions) for the list of codes.
|
|
470
|
+
*
|
|
471
|
+
* **Example:** Pin a region
|
|
472
|
+
* ```typescript
|
|
473
|
+
* const web = yield* Fly.Machine("Web", {
|
|
474
|
+
* app: Site,
|
|
475
|
+
* region: "ewr",
|
|
476
|
+
* image: "nginx:alpine",
|
|
477
|
+
* });
|
|
478
|
+
* ```
|
|
479
|
+
*
|
|
480
|
+
* :::caution[Changing `region` replaces the Machine]
|
|
481
|
+
* The Machine is created in the new region. The old one is deleted.
|
|
482
|
+
* :::
|
|
483
|
+
*
|
|
484
|
+
* ### Guest size
|
|
485
|
+
* `guest` is CPU kind, CPU count, and memory. Default is shared-cpu,
|
|
486
|
+
* 1 CPU, 256 MB. Rolling updates guest sizing in place; blue/green replaces
|
|
487
|
+
* the Machines.
|
|
488
|
+
*
|
|
489
|
+
* **Example:** Shared CPU
|
|
490
|
+
* ```typescript
|
|
491
|
+
* const web = yield* Fly.Machine("Web", {
|
|
492
|
+
* app: Site,
|
|
493
|
+
* region: "iad",
|
|
494
|
+
* image: "nginx:alpine",
|
|
495
|
+
* guest: { cpuKind: "shared", cpus: 1, memoryMb: 256 },
|
|
496
|
+
* });
|
|
497
|
+
* ```
|
|
498
|
+
*
|
|
499
|
+
* ### GPU
|
|
500
|
+
* Set `gpuKind` and `gpus` on `guest` when the Machine should have a
|
|
501
|
+
* GPU.
|
|
502
|
+
*
|
|
503
|
+
* **Example:** GPU guest
|
|
504
|
+
* ```typescript
|
|
505
|
+
* const worker = yield* Fly.Machine("Worker", {
|
|
506
|
+
* app: Site,
|
|
507
|
+
* region: "iad",
|
|
508
|
+
* image: "my-gpu-image:tag",
|
|
509
|
+
* guest: {
|
|
510
|
+
* cpuKind: "performance",
|
|
511
|
+
* cpus: 2,
|
|
512
|
+
* memoryMb: 4096,
|
|
513
|
+
* gpuKind: "a10",
|
|
514
|
+
* gpus: 1,
|
|
515
|
+
* },
|
|
516
|
+
* });
|
|
517
|
+
* ```
|
|
518
|
+
*
|
|
519
|
+
* ### Environment variables
|
|
520
|
+
* `env` is merged onto the Machine. Fly also injects App
|
|
521
|
+
* {@link Secret} values as env vars unless the Machine skips secrets.
|
|
522
|
+
*
|
|
523
|
+
* **Example:** Set env
|
|
524
|
+
* ```typescript
|
|
525
|
+
* const worker = yield* Fly.Machine("Worker", {
|
|
526
|
+
* app: Site,
|
|
527
|
+
* region: "iad",
|
|
528
|
+
* image: "my-image:tag",
|
|
529
|
+
* env: { LOG_LEVEL: "info" },
|
|
530
|
+
* });
|
|
531
|
+
* ```
|
|
532
|
+
*
|
|
533
|
+
* ### Publish a proxy service
|
|
534
|
+
* `services` publishes ports on Fly's proxy. The App needs an
|
|
535
|
+
* {@link IpAssignment} before `{app}.fly.dev` answers. For a public
|
|
536
|
+
* endpoint without managing Apps and addresses, use a {@link Service}.
|
|
537
|
+
*
|
|
538
|
+
* Handlers are `http`, `tls`, `pg_tls`, and similar. Set `forceHttps`
|
|
539
|
+
* to redirect HTTP to HTTPS. Use `startPort` / `endPort` for a
|
|
540
|
+
* published range.
|
|
541
|
+
*
|
|
542
|
+
* Omit `services` (or pass `[]`) for a process that should not be
|
|
543
|
+
* reachable from the internet.
|
|
544
|
+
*
|
|
545
|
+
* **Example:** HTTP on port 80
|
|
546
|
+
* ```typescript
|
|
547
|
+
* const web = yield* Fly.Machine("Web", {
|
|
548
|
+
* app: Site,
|
|
549
|
+
* region: "iad",
|
|
550
|
+
* image: "nginx:alpine",
|
|
551
|
+
* services: [
|
|
552
|
+
* {
|
|
553
|
+
* protocol: "tcp",
|
|
554
|
+
* internalPort: 80,
|
|
555
|
+
* ports: [
|
|
556
|
+
* { port: 80, handlers: ["http"], forceHttps: true },
|
|
557
|
+
* { port: 443, handlers: ["tls", "http"] },
|
|
558
|
+
* ],
|
|
559
|
+
* },
|
|
560
|
+
* ],
|
|
561
|
+
* });
|
|
562
|
+
* ```
|
|
563
|
+
*
|
|
564
|
+
* ### Service health checks
|
|
565
|
+
* Add HTTP or TCP `checks` to a service. Fly uses their results to
|
|
566
|
+
* determine whether the service is ready to receive traffic. With rolling
|
|
567
|
+
* updates, reconcile waits for each started replica's checks before updating
|
|
568
|
+
* the next replica. Missing or non-passing results are polled within
|
|
569
|
+
* `deploy.healthTimeout` (60 seconds by default), then fail deployment with
|
|
570
|
+
* `Fly.ReplicaChecksNotPassing`. Later replicas remain unchanged; earlier
|
|
571
|
+
* updates are not rolled back. A single rolling replica can be unavailable.
|
|
572
|
+
* Blue/green checks replacements before retiring the old set, with
|
|
573
|
+
* representative/floor readiness for idle capacity.
|
|
574
|
+
*
|
|
575
|
+
* **Example:** HTTP readiness check
|
|
576
|
+
* ```typescript
|
|
577
|
+
* const web = yield* Fly.Machine("Web", {
|
|
578
|
+
* app: Site,
|
|
579
|
+
* region: "iad",
|
|
580
|
+
* image: "nginx:alpine",
|
|
581
|
+
* services: [
|
|
582
|
+
* {
|
|
583
|
+
* protocol: "tcp",
|
|
584
|
+
* internalPort: 80,
|
|
585
|
+
* ports: [{ port: 80, handlers: ["http"] }],
|
|
586
|
+
* checks: [
|
|
587
|
+
* {
|
|
588
|
+
* type: "http",
|
|
589
|
+
* port: 80,
|
|
590
|
+
* method: "GET",
|
|
591
|
+
* path: "/",
|
|
592
|
+
* protocol: "http",
|
|
593
|
+
* interval: "15s",
|
|
594
|
+
* timeout: "2s",
|
|
595
|
+
* gracePeriod: "30s",
|
|
596
|
+
* headers: [{ name: "X-Health-Check", values: ["alchemy"] }],
|
|
597
|
+
* },
|
|
598
|
+
* ],
|
|
599
|
+
* },
|
|
600
|
+
* ],
|
|
601
|
+
* });
|
|
602
|
+
* ```
|
|
603
|
+
*
|
|
604
|
+
* ### Autostart and autostop
|
|
605
|
+
* `autostart` starts the Machine when a request arrives. `autostop` is
|
|
606
|
+
* `"off"`, `"stop"`, `"suspend"`, or a boolean. `minMachinesRunning`
|
|
607
|
+
* keeps that many Machines up for the service.
|
|
608
|
+
*
|
|
609
|
+
* Autostop only affects Machines that already exist. Set `count` or declare
|
|
610
|
+
* more resources to size the pool. Stop boots a new process on autostart;
|
|
611
|
+
* suspend may resume memory or fall back to a cold start. Suspension is not
|
|
612
|
+
* SIGTERM shutdown and does not run ordinary shutdown finalizers.
|
|
613
|
+
*
|
|
614
|
+
* Blue/green supports both policies: it checks a representative and the
|
|
615
|
+
* required running floor while preserving idle nonrepresentatives. It
|
|
616
|
+
* restores the requested idle policy before retiring predecessors and
|
|
617
|
+
* checks any new instance created by restoration. A replacement does not
|
|
618
|
+
* inherit its suspended predecessor's process memory.
|
|
619
|
+
*
|
|
620
|
+
* **Example:** Stop when idle
|
|
621
|
+
* ```typescript
|
|
622
|
+
* const web = yield* Fly.Machine("Web", {
|
|
623
|
+
* app: Site,
|
|
624
|
+
* region: "iad",
|
|
625
|
+
* image: "nginx:alpine",
|
|
626
|
+
* services: [
|
|
627
|
+
* {
|
|
628
|
+
* protocol: "tcp",
|
|
629
|
+
* internalPort: 80,
|
|
630
|
+
* autostart: true,
|
|
631
|
+
* autostop: "stop",
|
|
632
|
+
* minMachinesRunning: 0,
|
|
633
|
+
* ports: [{ port: 80, handlers: ["http"] }],
|
|
634
|
+
* },
|
|
635
|
+
* ],
|
|
636
|
+
* });
|
|
637
|
+
* ```
|
|
638
|
+
*
|
|
639
|
+
* ### Scale up
|
|
640
|
+
* Each Machine resource runs one VM by default. Set `count` to manage
|
|
641
|
+
* several replicas together, or declare separate resources for Machines
|
|
642
|
+
* with different configuration. Fly's proxy load-balances published
|
|
643
|
+
* `services` across them.
|
|
644
|
+
*
|
|
645
|
+
* Both Machine and {@link Service} support `count`. Default rolling updates
|
|
646
|
+
* replicas sequentially; blue/green prepares replacements before retirement.
|
|
647
|
+
* Separate resources do not share an update order or App-wide lease lock.
|
|
648
|
+
*
|
|
649
|
+
* **Example:** Two Machines
|
|
650
|
+
* ```typescript
|
|
651
|
+
* const web1 = yield* Fly.Machine("Web1", {
|
|
652
|
+
* app: Site,
|
|
653
|
+
* region: "iad",
|
|
654
|
+
* image: "nginx:alpine",
|
|
655
|
+
* services: [
|
|
656
|
+
* {
|
|
657
|
+
* protocol: "tcp",
|
|
658
|
+
* internalPort: 80,
|
|
659
|
+
* ports: [{ port: 80, handlers: ["http"] }],
|
|
660
|
+
* },
|
|
661
|
+
* ],
|
|
662
|
+
* });
|
|
663
|
+
*
|
|
664
|
+
* const web2 = yield* Fly.Machine("Web2", {
|
|
665
|
+
* app: Site,
|
|
666
|
+
* region: "iad",
|
|
667
|
+
* image: "nginx:alpine",
|
|
668
|
+
* services: [
|
|
669
|
+
* {
|
|
670
|
+
* protocol: "tcp",
|
|
671
|
+
* internalPort: 80,
|
|
672
|
+
* ports: [{ port: 80, handlers: ["http"] }],
|
|
673
|
+
* },
|
|
674
|
+
* ],
|
|
675
|
+
* });
|
|
676
|
+
* ```
|
|
677
|
+
*
|
|
678
|
+
* ### Scale down
|
|
679
|
+
* Remove a Machine from the stack. The next deploy deletes it.
|
|
680
|
+
*
|
|
681
|
+
* **Example:** Drop Web2
|
|
682
|
+
* ```diff
|
|
683
|
+
* const web1 = yield* Fly.Machine("Web1", {
|
|
684
|
+
* app: Site,
|
|
685
|
+
* region: "iad",
|
|
686
|
+
* image: "nginx:alpine",
|
|
687
|
+
* });
|
|
688
|
+
* -
|
|
689
|
+
* - const web2 = yield* Fly.Machine("Web2", {
|
|
690
|
+
* - app: Site,
|
|
691
|
+
* - region: "iad",
|
|
692
|
+
* - image: "nginx:alpine",
|
|
693
|
+
* - });
|
|
694
|
+
* ```
|
|
695
|
+
*
|
|
696
|
+
* ### Attach a disk
|
|
697
|
+
* Pass disks as `mounts`. Alchemy creates a Volume in the Machine's
|
|
698
|
+
* app and region. A Volume attaches to one Machine. There is no
|
|
699
|
+
* standalone Volume resource.
|
|
700
|
+
*
|
|
701
|
+
* `sizeGb` can grow in place. Shrinking is not supported. Encryption,
|
|
702
|
+
* filesystem type, `snapshotId`, and `sourceVolumeId` are create-only.
|
|
703
|
+
* See {@link MountVolume} for the full disk spec. From a Service,
|
|
704
|
+
* prefer `MountVolume` so the path is part of the binding graph.
|
|
705
|
+
*
|
|
706
|
+
* **Example:** Mount `/data`
|
|
707
|
+
* ```typescript
|
|
708
|
+
* const box = yield* Fly.Machine("Box", {
|
|
709
|
+
* app: Site,
|
|
710
|
+
* region: "iad",
|
|
711
|
+
* image: "postgres:16",
|
|
712
|
+
* mounts: [{ path: "/data", sizeGb: 10 }],
|
|
713
|
+
* });
|
|
714
|
+
* ```
|
|
715
|
+
*
|
|
716
|
+
* ### Init
|
|
717
|
+
* `init` overrides `cmd`, `entrypoint`, `exec`, swap, and TTY. Updates
|
|
718
|
+
* in place.
|
|
719
|
+
*
|
|
720
|
+
* **Example:** Custom command
|
|
721
|
+
* ```typescript
|
|
722
|
+
* const box = yield* Fly.Machine("Box", {
|
|
723
|
+
* app: Site,
|
|
724
|
+
* region: "iad",
|
|
725
|
+
* image: "postgres:16",
|
|
726
|
+
* init: { cmd: ["postgres", "-c", "shared_buffers=256MB"] },
|
|
727
|
+
* });
|
|
728
|
+
* ```
|
|
729
|
+
*
|
|
730
|
+
* ### Restart policy
|
|
731
|
+
* `restart.policy` is `"no"`, `"always"`, `"on-failure"`, or
|
|
732
|
+
* `"spot-price"`. `maxRetries` applies when the policy is
|
|
733
|
+
* `"on-failure"`. Updates in place.
|
|
734
|
+
*
|
|
735
|
+
* **Example:** Always restart
|
|
736
|
+
* ```typescript
|
|
737
|
+
* const worker = yield* Fly.Machine("Worker", {
|
|
738
|
+
* app: Site,
|
|
739
|
+
* region: "iad",
|
|
740
|
+
* image: "my-image:tag",
|
|
741
|
+
* restart: { policy: "always" },
|
|
742
|
+
* });
|
|
743
|
+
* ```
|
|
744
|
+
*
|
|
745
|
+
* ### Destroy on exit
|
|
746
|
+
* `autoDestroy: true` tears the Machine down when its main process
|
|
747
|
+
* exits. Default is `false`.
|
|
748
|
+
*
|
|
749
|
+
* **Example:** One-shot Machine
|
|
750
|
+
* ```typescript
|
|
751
|
+
* const job = yield* Fly.Machine("Job", {
|
|
752
|
+
* app: Site,
|
|
753
|
+
* region: "iad",
|
|
754
|
+
* image: "my-job:tag",
|
|
755
|
+
* autoDestroy: true,
|
|
756
|
+
* restart: { policy: "no" },
|
|
757
|
+
* });
|
|
758
|
+
* ```
|
|
759
|
+
*
|
|
760
|
+
* ### Skip launch
|
|
761
|
+
* `skipLaunch: true` creates or updates the config without starting
|
|
762
|
+
* the Machine. Default is `false`. Reconcile otherwise waits until
|
|
763
|
+
* the Machine is `started`, and until service checks are passing when
|
|
764
|
+
* the Machine has them.
|
|
765
|
+
*
|
|
766
|
+
* **Example:** Config only
|
|
767
|
+
* ```typescript
|
|
768
|
+
* const web = yield* Fly.Machine("Web", {
|
|
769
|
+
* app: Site,
|
|
770
|
+
* region: "iad",
|
|
771
|
+
* image: "nginx:alpine",
|
|
772
|
+
* skipLaunch: true,
|
|
773
|
+
* });
|
|
774
|
+
* ```
|
|
775
|
+
*
|
|
776
|
+
* ### Metadata
|
|
777
|
+
* User keys on `metadata` merge with Alchemy ownership keys
|
|
778
|
+
* (`alchemy.stack`, `alchemy.stage`, `alchemy.id`, `alchemy.type`,
|
|
779
|
+
* `alchemy.replica`). Those ownership keys are always written so
|
|
780
|
+
* `list()` can find owned Machines. Fly Apps have no labels.
|
|
781
|
+
*
|
|
782
|
+
* **Example:** User metadata
|
|
783
|
+
* ```typescript
|
|
784
|
+
* const web = yield* Fly.Machine("Web", {
|
|
785
|
+
* app: Site,
|
|
786
|
+
* region: "iad",
|
|
787
|
+
* image: "nginx:alpine",
|
|
788
|
+
* metadata: { role: "edge" },
|
|
789
|
+
* });
|
|
790
|
+
* ```
|
|
791
|
+
*
|
|
792
|
+
* ### Secrets version
|
|
793
|
+
* `minSecretsVersion` requires at least that App-secrets version, not an
|
|
794
|
+
* immutable snapshot. Machine leases do not serialize vault writers.
|
|
795
|
+
* After rotating a {@link Secret}, declare the required floor or another
|
|
796
|
+
* explicit rollout input; an out-of-band change alone does not watch/redeploy.
|
|
797
|
+
*
|
|
798
|
+
* **Example:** Wait for secrets
|
|
799
|
+
* ```typescript
|
|
800
|
+
* const web = yield* Fly.Machine("Web", {
|
|
801
|
+
* app: Site,
|
|
802
|
+
* region: "iad",
|
|
803
|
+
* image: "nginx:alpine",
|
|
804
|
+
* minSecretsVersion: 2,
|
|
805
|
+
* });
|
|
806
|
+
* ```
|
|
807
|
+
*
|
|
808
|
+
* ### Blue/green deployments
|
|
809
|
+
* Prepare a healthy replacement set before retiring the current Machines.
|
|
810
|
+
* Physical IDs and names change; the App URL remains stable. Volumes,
|
|
811
|
+
* auto-destroy, and skipLaunch are incompatible. Autostop preserves idle
|
|
812
|
+
* nonrepresentatives while a representative passes checks. Raw images must
|
|
813
|
+
* handle their own shutdown signal and stop accepting background work.
|
|
814
|
+
*
|
|
815
|
+
* Retirement honors each predecessor's own signal and timeout. Native
|
|
816
|
+
* target leases do not exclude every simultaneous first deployment or
|
|
817
|
+
* snapshot; serialize CI for the same resource. See the
|
|
818
|
+
* [deployment guide](/fly/compute/deployments) for idle capacity, secret
|
|
819
|
+
* floors, recovery, and the limits of live-tested parity.
|
|
820
|
+
*
|
|
821
|
+
* **Example:** Private worker readiness
|
|
822
|
+
* ```typescript
|
|
823
|
+
* const worker = yield* Fly.Machine("Worker", {
|
|
824
|
+
* app: Site,
|
|
825
|
+
* image: "registry.example.com/worker:v2",
|
|
826
|
+
* deploy: { strategy: "bluegreen", healthTimeout: "60 seconds" },
|
|
827
|
+
* shutdown: { signal: "SIGTERM", timeout: "30 seconds" },
|
|
828
|
+
* checks: {
|
|
829
|
+
* ready: { type: "http", port: 3000, path: "/healthz", interval: "5s", timeout: "2s" },
|
|
830
|
+
* },
|
|
831
|
+
* });
|
|
832
|
+
* ```
|
|
833
|
+
*
|
|
834
|
+
* Every published service needs its own service check. Before promotion, a
|
|
835
|
+
* failed candidate leaves the old generation serving. After possible promotion,
|
|
836
|
+
* potentially serving replacements are preserved rather than blindly deleted.
|
|
837
|
+
* Retry an interrupted deploy to finish promotion or retirement; destroy
|
|
838
|
+
* discovers unfinished owned generations.
|
|
839
|
+
* See the [deployment guide](/fly/compute/deployments) for recovery and limits.
|
|
840
|
+
*
|
|
841
|
+
* @resource
|
|
842
|
+
* @product Machine
|
|
843
|
+
*/
|
|
844
|
+
export const Machine = Resource<Machine>("Fly.Machine");
|
|
845
|
+
|
|
846
|
+
export class MachineNotCreated extends Data.TaggedError("Fly.MachineNotCreated")<{
|
|
847
|
+
name: string;
|
|
848
|
+
appName: string;
|
|
849
|
+
}> {}
|
|
850
|
+
|
|
851
|
+
export class MachineAppNotResolved extends Data.TaggedError("Fly.MachineAppNotResolved")<{
|
|
852
|
+
message: string;
|
|
853
|
+
}> {}
|
|
854
|
+
|
|
855
|
+
type MachineBinding = Machine["Binding"];
|
|
856
|
+
|
|
857
|
+
const appNameOf = (value: unknown): string | undefined => {
|
|
858
|
+
if (value == null || typeof value !== "object") return undefined;
|
|
859
|
+
const name = (value as { appName?: unknown }).appName;
|
|
860
|
+
return typeof name === "string" && name.length > 0 ? name : undefined;
|
|
861
|
+
};
|
|
862
|
+
|
|
863
|
+
const compactRecord = (
|
|
864
|
+
record: Record<string, string | undefined> | null | undefined,
|
|
865
|
+
): Record<string, string> =>
|
|
866
|
+
Object.fromEntries(
|
|
867
|
+
Object.entries(record ?? {}).flatMap(([key, value]) =>
|
|
868
|
+
value === undefined ? [] : [[key, value]],
|
|
869
|
+
),
|
|
870
|
+
);
|
|
871
|
+
|
|
872
|
+
const toEnv = toEnvRecord;
|
|
873
|
+
|
|
874
|
+
const resolveMachineName = (id: string, name: string | undefined, existing?: string) =>
|
|
875
|
+
Effect.gen(function* () {
|
|
876
|
+
if (name !== undefined) return sanitizeFlyAppName(name);
|
|
877
|
+
if (existing !== undefined) return existing;
|
|
878
|
+
return yield* createFlyResourceName(id);
|
|
879
|
+
});
|
|
880
|
+
|
|
881
|
+
const mergeBindings = (bindings: readonly ResourceBinding<MachineBinding>[]) => {
|
|
882
|
+
const env: Record<string, any> = {};
|
|
883
|
+
const mounts: DiskSpec[] = [];
|
|
884
|
+
for (const binding of bindings) {
|
|
885
|
+
Object.assign(env, binding.data?.env);
|
|
886
|
+
if (binding.data?.mounts) mounts.push(...binding.data.mounts);
|
|
887
|
+
}
|
|
888
|
+
return { env, mounts };
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
const mergeDisks = (props: DiskSpec[] | undefined, bindingMounts: DiskSpec[]): DiskSpec[] => {
|
|
892
|
+
const byPath = new Map<string, DiskSpec>();
|
|
893
|
+
for (const disk of [...(props ?? []), ...bindingMounts]) {
|
|
894
|
+
byPath.set(disk.path, disk);
|
|
895
|
+
}
|
|
896
|
+
return [...byPath.values()];
|
|
897
|
+
};
|
|
898
|
+
|
|
899
|
+
const toFlyGuest = (guest: MachineGuest | undefined): FlyMachineGuest => {
|
|
900
|
+
const fly: FlyMachineGuest = {
|
|
901
|
+
cpu_kind: guest?.cpuKind ?? DEFAULT_CPU_KIND,
|
|
902
|
+
cpus: guest?.cpus ?? DEFAULT_CPUS,
|
|
903
|
+
memory_mb: guest?.memoryMb ?? DEFAULT_MEMORY_MB,
|
|
904
|
+
};
|
|
905
|
+
if (guest?.gpuKind !== undefined) fly.gpu_kind = guest.gpuKind;
|
|
906
|
+
if (guest?.gpus !== undefined) fly.gpus = guest.gpus;
|
|
907
|
+
return fly;
|
|
908
|
+
};
|
|
909
|
+
|
|
910
|
+
const toFlyInit = (init: MachineInit): FlyMachineInit => ({
|
|
911
|
+
cmd: init.cmd,
|
|
912
|
+
entrypoint: init.entrypoint,
|
|
913
|
+
exec: init.exec,
|
|
914
|
+
swap_size_mb: init.swapSizeMb,
|
|
915
|
+
tty: init.tty,
|
|
916
|
+
});
|
|
917
|
+
|
|
918
|
+
const toFlyRestart = (restart: MachineRestart): FlyMachineRestart => ({
|
|
919
|
+
policy: restart.policy,
|
|
920
|
+
max_retries: restart.maxRetries,
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
const desiredEnv = (
|
|
924
|
+
props: MachineProps,
|
|
925
|
+
bindingEnv: Record<string, any>,
|
|
926
|
+
): Record<string, string> => ({ ...toEnv(props.env), ...toEnv(bindingEnv) });
|
|
927
|
+
|
|
928
|
+
const desiredMetadata = (
|
|
929
|
+
props: MachineProps,
|
|
930
|
+
alchemy: Record<string, string>,
|
|
931
|
+
): Record<string, string> => ({ ...(props.metadata ?? {}), ...alchemy });
|
|
932
|
+
|
|
933
|
+
const buildConfig = (input: {
|
|
934
|
+
image: string | undefined;
|
|
935
|
+
containers: FlyMachineConfig["containers"];
|
|
936
|
+
guest: FlyMachineGuest;
|
|
937
|
+
env: Record<string, string>;
|
|
938
|
+
services: FlyMachineService[] | undefined;
|
|
939
|
+
mounts: FlyMachineMount[];
|
|
940
|
+
metadata: Record<string, string>;
|
|
941
|
+
restart: FlyMachineRestart | undefined;
|
|
942
|
+
autoDestroy: boolean | undefined;
|
|
943
|
+
init: FlyMachineInit | undefined;
|
|
944
|
+
}): FlyMachineConfig => ({
|
|
945
|
+
image: input.image,
|
|
946
|
+
containers: input.containers,
|
|
947
|
+
guest: input.guest,
|
|
948
|
+
env: Object.keys(input.env).length > 0 ? input.env : undefined,
|
|
949
|
+
services: input.services !== undefined && input.services.length > 0 ? input.services : undefined,
|
|
950
|
+
mounts: input.mounts.length > 0 ? input.mounts : undefined,
|
|
951
|
+
metadata: input.metadata,
|
|
952
|
+
restart: input.restart,
|
|
953
|
+
auto_destroy: input.autoDestroy,
|
|
954
|
+
init: input.init,
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
const sameImage = (machine: FlyMachine, image: string) => {
|
|
958
|
+
const configImage = machine.config?.image;
|
|
959
|
+
if (configImage === image) return true;
|
|
960
|
+
const ref = machine.image_ref;
|
|
961
|
+
const colon = image.lastIndexOf(":");
|
|
962
|
+
const slash = image.lastIndexOf("/");
|
|
963
|
+
const split = colon > slash ? colon : -1;
|
|
964
|
+
const repo = split === -1 ? image : image.slice(0, split);
|
|
965
|
+
const tag = split === -1 ? "latest" : image.slice(split + 1);
|
|
966
|
+
const observedRepo = ref?.repository;
|
|
967
|
+
if (observedRepo === undefined || ref?.tag !== tag) return false;
|
|
968
|
+
return observedRepo === repo || observedRepo.endsWith(`/${repo}`);
|
|
969
|
+
};
|
|
970
|
+
|
|
971
|
+
const sameGuest = (observed: FlyMachineGuest | undefined, desired: FlyMachineGuest) =>
|
|
972
|
+
(observed?.cpu_kind ?? DEFAULT_CPU_KIND) === desired.cpu_kind &&
|
|
973
|
+
(observed?.cpus ?? DEFAULT_CPUS) === desired.cpus &&
|
|
974
|
+
(observed?.memory_mb ?? DEFAULT_MEMORY_MB) === desired.memory_mb &&
|
|
975
|
+
observed?.gpu_kind === desired.gpu_kind &&
|
|
976
|
+
observed?.gpus === desired.gpus;
|
|
977
|
+
|
|
978
|
+
const sameEnv = (
|
|
979
|
+
observed: Record<string, string | undefined> | undefined,
|
|
980
|
+
desired: Record<string, string>,
|
|
981
|
+
) => deepEqual(compactRecord(observed), desired);
|
|
982
|
+
|
|
983
|
+
const sameMounts = (observed: FlyMachineMount[] | undefined, desired: FlyMachineMount[]) => {
|
|
984
|
+
const key = (mount: FlyMachineMount) => `${mount.volume ?? ""}:${mount.path ?? ""}`;
|
|
985
|
+
const left = [...(observed ?? [])].map(key).sort();
|
|
986
|
+
const right = desired.map(key).sort();
|
|
987
|
+
return deepEqual(left, right);
|
|
988
|
+
};
|
|
989
|
+
|
|
990
|
+
const sameRestart = (
|
|
991
|
+
observed: FlyMachineRestart | undefined,
|
|
992
|
+
desired: FlyMachineRestart | undefined,
|
|
993
|
+
) =>
|
|
994
|
+
deepEqual(
|
|
995
|
+
{ policy: observed?.policy ?? "on-failure", max_retries: observed?.max_retries ?? 10 },
|
|
996
|
+
{ policy: desired?.policy ?? "on-failure", max_retries: desired?.max_retries ?? 10 },
|
|
997
|
+
{ stripNullish: true },
|
|
998
|
+
);
|
|
999
|
+
|
|
1000
|
+
const sameInit = (observed: FlyMachineInit | undefined, desired: FlyMachineInit | undefined) =>
|
|
1001
|
+
deepEqual(observed ?? {}, desired ?? {}, { stripNullish: true });
|
|
1002
|
+
|
|
1003
|
+
const metadataChanged = (
|
|
1004
|
+
observed: Record<string, string | undefined> | undefined,
|
|
1005
|
+
desired: Record<string, string>,
|
|
1006
|
+
) => {
|
|
1007
|
+
const { removed, added, updated } = diffMachineMetadata(compactRecord(observed), desired);
|
|
1008
|
+
return removed.length > 0 || Object.keys(added).length > 0 || Object.keys(updated).length > 0;
|
|
1009
|
+
};
|
|
1010
|
+
|
|
1011
|
+
const configDrifted = (
|
|
1012
|
+
machine: FlyMachine,
|
|
1013
|
+
desired: {
|
|
1014
|
+
image: string | undefined;
|
|
1015
|
+
containers: FlyMachineConfig["containers"];
|
|
1016
|
+
guest: FlyMachineGuest;
|
|
1017
|
+
env: Record<string, string>;
|
|
1018
|
+
services: FlyMachineService[] | undefined;
|
|
1019
|
+
mounts: FlyMachineMount[];
|
|
1020
|
+
metadata: Record<string, string>;
|
|
1021
|
+
restart: FlyMachineRestart | undefined;
|
|
1022
|
+
autoDestroy: boolean | undefined;
|
|
1023
|
+
init: FlyMachineInit | undefined;
|
|
1024
|
+
},
|
|
1025
|
+
) => {
|
|
1026
|
+
const config = machine.config;
|
|
1027
|
+
return (
|
|
1028
|
+
(desired.containers !== undefined
|
|
1029
|
+
? !sameContainerWorkload(config, desired.containers)
|
|
1030
|
+
: desired.image === undefined ||
|
|
1031
|
+
!sameImage(machine, desired.image) ||
|
|
1032
|
+
(config?.containers?.length ?? 0) > 0) ||
|
|
1033
|
+
!sameGuest(config?.guest, desired.guest) ||
|
|
1034
|
+
!sameEnv(config?.env, desired.env) ||
|
|
1035
|
+
!sameServices(config?.services, desired.services) ||
|
|
1036
|
+
!sameMounts(config?.mounts, desired.mounts) ||
|
|
1037
|
+
metadataChanged(config?.metadata, desired.metadata) ||
|
|
1038
|
+
!sameRestart(config?.restart, desired.restart) ||
|
|
1039
|
+
(desired.autoDestroy ?? false) !== (config?.auto_destroy ?? false) ||
|
|
1040
|
+
!sameInit(config?.init, desired.init)
|
|
1041
|
+
);
|
|
1042
|
+
};
|
|
1043
|
+
|
|
1044
|
+
const toAttrs = (set: ReplicaSet): Machine["Attributes"] => ({
|
|
1045
|
+
appName: set.appName,
|
|
1046
|
+
rolloutPending: set.rolloutPending,
|
|
1047
|
+
machineId: set.machineId,
|
|
1048
|
+
machineIds: set.machineIds,
|
|
1049
|
+
name: set.name,
|
|
1050
|
+
baseName: set.baseName,
|
|
1051
|
+
region: set.region,
|
|
1052
|
+
state: set.state,
|
|
1053
|
+
instanceId: set.instanceId,
|
|
1054
|
+
privateIp: set.privateIp,
|
|
1055
|
+
imageRef: set.imageRef,
|
|
1056
|
+
guest: set.guest,
|
|
1057
|
+
count: set.count,
|
|
1058
|
+
mounts: set.mounts,
|
|
1059
|
+
replicas: set.replicas,
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1062
|
+
const machineIdsOf = (output: Machine["Attributes"] | undefined) =>
|
|
1063
|
+
output?.machineIds ??
|
|
1064
|
+
(output?.machineId !== undefined && output.machineId.length > 0 ? [output.machineId] : []);
|
|
1065
|
+
|
|
1066
|
+
export const MachineProvider = () =>
|
|
1067
|
+
Provider.succeed(Machine, {
|
|
1068
|
+
stables: ["region", "appName"],
|
|
1069
|
+
nuke: { dependsOn: ["Fly.App"] },
|
|
1070
|
+
|
|
1071
|
+
diff: Effect.fn(function* ({ news, output }) {
|
|
1072
|
+
if (news === undefined) return;
|
|
1073
|
+
if ("app" in news) {
|
|
1074
|
+
const imageMode = { image: news.image, containers: news.containers, init: news.init };
|
|
1075
|
+
const imageModeResolved =
|
|
1076
|
+
isResolved<Pick<MachineProps, "image" | "containers" | "init">>(imageMode);
|
|
1077
|
+
if (imageModeResolved) yield* validateMachineContainers(imageMode);
|
|
1078
|
+
const settings: Input<
|
|
1079
|
+
Pick<
|
|
1080
|
+
MachineProps,
|
|
1081
|
+
| "deploy"
|
|
1082
|
+
| "shutdown"
|
|
1083
|
+
| "checks"
|
|
1084
|
+
| "services"
|
|
1085
|
+
| "mounts"
|
|
1086
|
+
| "skipLaunch"
|
|
1087
|
+
| "autoDestroy"
|
|
1088
|
+
| "restart"
|
|
1089
|
+
| "containers"
|
|
1090
|
+
>
|
|
1091
|
+
> = {
|
|
1092
|
+
deploy: news.deploy,
|
|
1093
|
+
shutdown: news.shutdown,
|
|
1094
|
+
checks: news.checks,
|
|
1095
|
+
services: news.services,
|
|
1096
|
+
mounts: news.mounts,
|
|
1097
|
+
skipLaunch: news.skipLaunch,
|
|
1098
|
+
autoDestroy: news.autoDestroy,
|
|
1099
|
+
restart: news.restart,
|
|
1100
|
+
containers: news.containers,
|
|
1101
|
+
};
|
|
1102
|
+
if (
|
|
1103
|
+
imageModeResolved &&
|
|
1104
|
+
isResolved<
|
|
1105
|
+
Pick<
|
|
1106
|
+
MachineProps,
|
|
1107
|
+
| "deploy"
|
|
1108
|
+
| "shutdown"
|
|
1109
|
+
| "checks"
|
|
1110
|
+
| "services"
|
|
1111
|
+
| "mounts"
|
|
1112
|
+
| "skipLaunch"
|
|
1113
|
+
| "autoDestroy"
|
|
1114
|
+
| "restart"
|
|
1115
|
+
| "containers"
|
|
1116
|
+
>
|
|
1117
|
+
>(settings)
|
|
1118
|
+
) {
|
|
1119
|
+
yield* validateDeployment(
|
|
1120
|
+
yield* deploymentPolicy(settings.deploy, settings.shutdown),
|
|
1121
|
+
{
|
|
1122
|
+
services: settings.services?.map(toFlyService),
|
|
1123
|
+
checks: settings.checks,
|
|
1124
|
+
auto_destroy: settings.autoDestroy,
|
|
1125
|
+
restart: settings.restart,
|
|
1126
|
+
containers:
|
|
1127
|
+
settings.containers === undefined
|
|
1128
|
+
? undefined
|
|
1129
|
+
: toFlyContainers(settings.containers),
|
|
1130
|
+
},
|
|
1131
|
+
(settings.mounts?.length ?? 0) > 0,
|
|
1132
|
+
settings.skipLaunch,
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
if (!isResolved(news))
|
|
1137
|
+
return output?.rolloutPending ? { action: "update" as const } : undefined;
|
|
1138
|
+
yield* validateMachineContainers(news);
|
|
1139
|
+
if (output === undefined) return undefined;
|
|
1140
|
+
const desiredAppName = appNameOf(news.app);
|
|
1141
|
+
const appChanged = desiredAppName !== undefined && desiredAppName !== output.appName;
|
|
1142
|
+
const desiredName =
|
|
1143
|
+
news.name !== undefined ? sanitizeFlyAppName(news.name) : (output.baseName ?? output.name);
|
|
1144
|
+
const nameChanged = desiredName !== (output.baseName ?? output.name);
|
|
1145
|
+
const desiredRegion = news.region ?? DEFAULT_REGION;
|
|
1146
|
+
const regionChanged = desiredRegion !== output.region;
|
|
1147
|
+
if (appChanged || nameChanged || regionChanged) {
|
|
1148
|
+
return {
|
|
1149
|
+
action: "replace" as const,
|
|
1150
|
+
// Name is unique per App — same name in a new region cannot coexist.
|
|
1151
|
+
deleteFirst: nameChanged === false && appChanged === false,
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
return output.rolloutPending ? { action: "update" as const } : undefined;
|
|
1155
|
+
}),
|
|
1156
|
+
|
|
1157
|
+
read: Effect.fn(function* ({ id, fqn, instanceId, olds, output }) {
|
|
1158
|
+
const appName = appNameOf(olds?.app) ?? output?.appName;
|
|
1159
|
+
const name = yield* resolveMachineName(id, olds?.name, output?.baseName ?? output?.name);
|
|
1160
|
+
const found = yield* observeReplicaSet({
|
|
1161
|
+
appName,
|
|
1162
|
+
id,
|
|
1163
|
+
type: "Fly.Machine",
|
|
1164
|
+
fqn,
|
|
1165
|
+
resourceInstanceId: instanceId,
|
|
1166
|
+
machineIds: machineIdsOf(output),
|
|
1167
|
+
baseName: name,
|
|
1168
|
+
});
|
|
1169
|
+
if (found === undefined) return undefined;
|
|
1170
|
+
return toAttrs(found);
|
|
1171
|
+
}),
|
|
1172
|
+
|
|
1173
|
+
list: Effect.fn(function* () {
|
|
1174
|
+
const sets = yield* listReplicaSets("Fly.Machine");
|
|
1175
|
+
return sets.map(toAttrs);
|
|
1176
|
+
}),
|
|
1177
|
+
|
|
1178
|
+
reconcile: Effect.fn(function* ({ id, fqn, instanceId, news, output, bindings }) {
|
|
1179
|
+
const props = news;
|
|
1180
|
+
yield* validateMachineContainers(props);
|
|
1181
|
+
const policy = yield* deploymentPolicy(props.deploy, props.shutdown);
|
|
1182
|
+
const appName = appNameOf(props.app) ?? output?.appName;
|
|
1183
|
+
if (appName === undefined) {
|
|
1184
|
+
return yield* new MachineAppNotResolved({
|
|
1185
|
+
message: "Fly.Machine requires a resolved App with appName.",
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1188
|
+
const name = yield* resolveMachineName(id, props.name, output?.baseName ?? output?.name);
|
|
1189
|
+
const region = props.region ?? output?.region ?? DEFAULT_REGION;
|
|
1190
|
+
const count = resolveCount(props.count);
|
|
1191
|
+
const skipLaunch = props.skipLaunch === true;
|
|
1192
|
+
const bound = mergeBindings(bindings ?? []);
|
|
1193
|
+
const disks = mergeDisks(props.mounts, bound.mounts);
|
|
1194
|
+
const env = desiredEnv(props, bound.env);
|
|
1195
|
+
const guest = toFlyGuest(props.guest);
|
|
1196
|
+
const services = props.services?.map(toFlyService);
|
|
1197
|
+
const restart = props.restart ? toFlyRestart(props.restart) : undefined;
|
|
1198
|
+
const init = props.init ? toFlyInit(props.init) : undefined;
|
|
1199
|
+
const containers =
|
|
1200
|
+
props.containers === undefined ? undefined : toFlyContainers(props.containers);
|
|
1201
|
+
|
|
1202
|
+
const set = yield* reconcileReplicas({
|
|
1203
|
+
id,
|
|
1204
|
+
type: "Fly.Machine",
|
|
1205
|
+
fqn,
|
|
1206
|
+
resourceInstanceId: instanceId,
|
|
1207
|
+
policy,
|
|
1208
|
+
checks: props.checks,
|
|
1209
|
+
appName,
|
|
1210
|
+
baseName: name,
|
|
1211
|
+
regions: [region],
|
|
1212
|
+
count,
|
|
1213
|
+
disks,
|
|
1214
|
+
skipLaunch,
|
|
1215
|
+
minSecretsVersion: props.minSecretsVersion,
|
|
1216
|
+
outputMachineIds: machineIdsOf(output),
|
|
1217
|
+
preferVolumeIds: (output?.replicas ?? []).map((replica) =>
|
|
1218
|
+
replica.mounts.map((mount) => mount.volumeId),
|
|
1219
|
+
),
|
|
1220
|
+
configDrifted: (machine, desired) =>
|
|
1221
|
+
configDrifted(machine, {
|
|
1222
|
+
image: props.image,
|
|
1223
|
+
containers,
|
|
1224
|
+
guest,
|
|
1225
|
+
env,
|
|
1226
|
+
services,
|
|
1227
|
+
mounts: desired.mounts,
|
|
1228
|
+
metadata: desiredMetadata(props, desired.metadata),
|
|
1229
|
+
restart,
|
|
1230
|
+
autoDestroy: props.autoDestroy,
|
|
1231
|
+
init,
|
|
1232
|
+
}),
|
|
1233
|
+
buildConfig: ({ mounts, metadata }) =>
|
|
1234
|
+
buildConfig({
|
|
1235
|
+
image: props.image,
|
|
1236
|
+
containers,
|
|
1237
|
+
guest,
|
|
1238
|
+
env,
|
|
1239
|
+
services,
|
|
1240
|
+
mounts,
|
|
1241
|
+
metadata: desiredMetadata(props, metadata),
|
|
1242
|
+
restart,
|
|
1243
|
+
autoDestroy: props.autoDestroy,
|
|
1244
|
+
init,
|
|
1245
|
+
}),
|
|
1246
|
+
}).pipe(
|
|
1247
|
+
Effect.catchTag("Fly.ReplicaNotCreated", (error) =>
|
|
1248
|
+
Effect.fail(new MachineNotCreated({ name: error.name, appName: error.appName })),
|
|
1249
|
+
),
|
|
1250
|
+
);
|
|
1251
|
+
return toAttrs(set);
|
|
1252
|
+
}),
|
|
1253
|
+
|
|
1254
|
+
delete: Effect.fn(function* ({ id, fqn, instanceId, olds, output, force }) {
|
|
1255
|
+
const appName = output.appName ?? appNameOf(olds.app);
|
|
1256
|
+
if (appName === undefined) return;
|
|
1257
|
+
yield* deleteReplicaSet({
|
|
1258
|
+
appName,
|
|
1259
|
+
id,
|
|
1260
|
+
type: "Fly.Machine",
|
|
1261
|
+
fqn,
|
|
1262
|
+
resourceInstanceId: instanceId,
|
|
1263
|
+
machineIds: machineIdsOf(output),
|
|
1264
|
+
volumeIds: volumeIdsOf(output),
|
|
1265
|
+
force,
|
|
1266
|
+
});
|
|
1267
|
+
}),
|
|
1268
|
+
});
|