@alchemy.run/fly 0.0.0-stage → 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 +61 -2
- 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 +97 -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/App.ts
ADDED
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
import type { App as FlyApp } from "@distilled.cloud/fly-io/machines";
|
|
2
|
+
import * as machines from "@distilled.cloud/fly-io/machines";
|
|
3
|
+
import * as Retry from "@distilled.cloud/fly-io/Retry";
|
|
4
|
+
import { Unowned } from "alchemy/AdoptPolicy";
|
|
5
|
+
import { isResolved } from "alchemy/Diff";
|
|
6
|
+
import * as Provider from "alchemy/Provider";
|
|
7
|
+
import { Resource, type ResourceBinding } from "alchemy/Resource";
|
|
8
|
+
import * as Data from "effect/Data";
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as FetchHttpClient from "effect/http/FetchHttpClient";
|
|
11
|
+
import * as HttpClient from "effect/http/HttpClient";
|
|
12
|
+
import * as HttpClientRequest from "effect/http/HttpClientRequest";
|
|
13
|
+
import * as Option from "effect/Option";
|
|
14
|
+
import * as Schedule from "effect/Schedule";
|
|
15
|
+
import { resolveOrgSlug } from "./Environment.ts";
|
|
16
|
+
import type { MachineService } from "./Machine.ts";
|
|
17
|
+
import {
|
|
18
|
+
createFlyAppName,
|
|
19
|
+
isAlchemyOwnedMetadata,
|
|
20
|
+
matchesAlchemyPhysicalName,
|
|
21
|
+
sanitizeFlyAppName,
|
|
22
|
+
} from "./Metadata.ts";
|
|
23
|
+
import { findPortConflict, portsOfProps, withBindingPort } from "./ports.ts";
|
|
24
|
+
import type { Providers } from "./Providers.ts";
|
|
25
|
+
import { DEFAULT_BINDING_PORT } from "./rpc.ts";
|
|
26
|
+
|
|
27
|
+
export class AppDeletionAmbiguous extends Data.TaggedError("Fly.AppDeletionAmbiguous")<{
|
|
28
|
+
appName: string;
|
|
29
|
+
evidence: string;
|
|
30
|
+
}> {
|
|
31
|
+
get message() {
|
|
32
|
+
return `Deletion of ${this.appName} is uncertain (${this.evidence}); reconcile the App before retrying or recreating its name. Machine leases cannot fence App deletion.`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface AppProps {
|
|
37
|
+
/**
|
|
38
|
+
* Fly App name. Globally unique, DNS-compatible (lowercase letters,
|
|
39
|
+
* digits, hyphens), must start with a letter, max 30 characters. If
|
|
40
|
+
* omitted, a unique name is generated from the stack, stage and logical
|
|
41
|
+
* ID. Changing it replaces the App.
|
|
42
|
+
*/
|
|
43
|
+
name?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Organization slug. Defaults to the current token's org
|
|
46
|
+
* (`getCurrentToken`). Changing it replaces the App.
|
|
47
|
+
*/
|
|
48
|
+
orgSlug?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Isolated network name. Immutable after create — changing it replaces
|
|
51
|
+
* the App.
|
|
52
|
+
*/
|
|
53
|
+
network?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Enable `*.{name}.fly.dev` subdomains. Create-only; ignored on update
|
|
56
|
+
* (Fly has no App update API).
|
|
57
|
+
*/
|
|
58
|
+
enableSubdomains?: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type App = Resource<
|
|
62
|
+
"Fly.App",
|
|
63
|
+
AppProps,
|
|
64
|
+
{
|
|
65
|
+
/** Fly App id. */
|
|
66
|
+
appId: string;
|
|
67
|
+
/** Physical Fly App name. */
|
|
68
|
+
appName: string;
|
|
69
|
+
/** Fly internal numeric id, if the API returned one. */
|
|
70
|
+
internalNumericId: number | undefined;
|
|
71
|
+
/** Isolated network name, if set. */
|
|
72
|
+
network: string | undefined;
|
|
73
|
+
/** Observed status (e.g. `deployed`, `pending`). */
|
|
74
|
+
status: string | undefined;
|
|
75
|
+
/** Organization slug. */
|
|
76
|
+
orgSlug: string | undefined;
|
|
77
|
+
/** Observed machine count. */
|
|
78
|
+
machineCount: number | undefined;
|
|
79
|
+
/** Observed volume count. */
|
|
80
|
+
volumeCount: number | undefined;
|
|
81
|
+
/** Public `https://{appName}.fly.dev` URL. */
|
|
82
|
+
url: string;
|
|
83
|
+
},
|
|
84
|
+
AppBinding,
|
|
85
|
+
Providers
|
|
86
|
+
>;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Binding contract accepted by {@link App}. Each {@link Service} placed in
|
|
90
|
+
* the App (`app` prop) reports the ports it publishes, so the App can
|
|
91
|
+
* reject two Services on the same port before either one is deployed.
|
|
92
|
+
*/
|
|
93
|
+
export interface AppBinding {
|
|
94
|
+
/** Logical id of the Service. */
|
|
95
|
+
service: string;
|
|
96
|
+
/** The Service's `services` prop; `undefined` for the default ports. */
|
|
97
|
+
services: MachineService[] | undefined;
|
|
98
|
+
/** The Service's `bindingPort` prop. */
|
|
99
|
+
bindingPort: number | undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* A Fly.App is a global namespace in your account. It contains Machines,
|
|
104
|
+
* Secrets, IPs, and certificates. A {@link Service} creates its own App,
|
|
105
|
+
* so declare an App yourself for {@link Machine}s, or to group Services
|
|
106
|
+
* that share Secrets or a custom domain (the Service `app` prop).
|
|
107
|
+
*
|
|
108
|
+
* @see https://fly.io/docs/machines/api/apps-resource/
|
|
109
|
+
*
|
|
110
|
+
* ### Create an App
|
|
111
|
+
* Alchemy generates a unique name unless you pass one. `url` is
|
|
112
|
+
* `https://{appName}.fly.dev`. Nothing answers there until a
|
|
113
|
+
* {@link Machine} (or a Service with `app`) publishes a proxy service and
|
|
114
|
+
* the App has an {@link IpAssignment}.
|
|
115
|
+
*
|
|
116
|
+
* **Example:** Generated name
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const site = yield* Fly.App("Site");
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* :::note
|
|
122
|
+
* Prefer omitting `name` in tests and CI so names stay unique and
|
|
123
|
+
* reclaimable.
|
|
124
|
+
* :::
|
|
125
|
+
*
|
|
126
|
+
* ### A stable hostname
|
|
127
|
+
* Pass `name` when you need a stable `fly.dev` hostname.
|
|
128
|
+
*
|
|
129
|
+
* **Example:** Explicit name
|
|
130
|
+
* ```typescript
|
|
131
|
+
* const site = yield* Fly.App("Site", {
|
|
132
|
+
* name: "my-site",
|
|
133
|
+
* });
|
|
134
|
+
* ```
|
|
135
|
+
*
|
|
136
|
+
* :::caution[Changing `name` replaces the App]
|
|
137
|
+
* Fly cannot have two Apps with the same name. Alchemy deletes the
|
|
138
|
+
* old App first, then creates the new one.
|
|
139
|
+
* :::
|
|
140
|
+
*
|
|
141
|
+
* ### Organization
|
|
142
|
+
* Org defaults to the current token. Pass `orgSlug` to pin it.
|
|
143
|
+
*
|
|
144
|
+
* **Example:** Pin an org
|
|
145
|
+
* ```typescript
|
|
146
|
+
* const site = yield* Fly.App("Site", {
|
|
147
|
+
* name: "my-site",
|
|
148
|
+
* orgSlug: "my-org",
|
|
149
|
+
* });
|
|
150
|
+
* ```
|
|
151
|
+
*
|
|
152
|
+
* :::caution[Changing `orgSlug` replaces the App]
|
|
153
|
+
* The App is created in the new org. The old App is deleted.
|
|
154
|
+
* :::
|
|
155
|
+
*
|
|
156
|
+
* ### Subdomains
|
|
157
|
+
* `enableSubdomains: true` turns on `*.{appName}.fly.dev`.
|
|
158
|
+
*
|
|
159
|
+
* **Example:** Enable subdomains
|
|
160
|
+
* ```typescript
|
|
161
|
+
* const site = yield* Fly.App("Site", {
|
|
162
|
+
* name: "my-site",
|
|
163
|
+
* enableSubdomains: true,
|
|
164
|
+
* });
|
|
165
|
+
* ```
|
|
166
|
+
*
|
|
167
|
+
* :::note[Create-only]
|
|
168
|
+
* Flipping `enableSubdomains` later is ignored.
|
|
169
|
+
* :::
|
|
170
|
+
*
|
|
171
|
+
* ### Isolated network
|
|
172
|
+
* `network` is an optional 6PN name.
|
|
173
|
+
*
|
|
174
|
+
* **Example:** Custom network
|
|
175
|
+
* ```typescript
|
|
176
|
+
* const site = yield* Fly.App("Site", {
|
|
177
|
+
* name: "my-site",
|
|
178
|
+
* network: "private",
|
|
179
|
+
* });
|
|
180
|
+
* ```
|
|
181
|
+
*
|
|
182
|
+
* :::caution[Changing `network` replaces the App]
|
|
183
|
+
* The App is recreated on the new network.
|
|
184
|
+
* :::
|
|
185
|
+
*
|
|
186
|
+
* ### Module-scope declarations
|
|
187
|
+
* Declare the App once. Pass it into every child. Resource-valued props
|
|
188
|
+
* accept the resource or an Effect producing it. Do not unwrap it just
|
|
189
|
+
* to pass it along.
|
|
190
|
+
*
|
|
191
|
+
* **Example:** Module-scope App
|
|
192
|
+
* ```typescript
|
|
193
|
+
* // src/app.ts
|
|
194
|
+
* import * as Fly from "@alchemy.run/fly";
|
|
195
|
+
*
|
|
196
|
+
* export const Site = Fly.App("Site");
|
|
197
|
+
* ```
|
|
198
|
+
*
|
|
199
|
+
* @resource
|
|
200
|
+
* @product App
|
|
201
|
+
*/
|
|
202
|
+
export const App = Resource<App>("Fly.App");
|
|
203
|
+
|
|
204
|
+
export class AppNotCreated extends Data.TaggedError("Fly.AppNotCreated")<{
|
|
205
|
+
name: string;
|
|
206
|
+
/** Fly's rejection of the create request, when there was one. */
|
|
207
|
+
reason?: string;
|
|
208
|
+
}> {
|
|
209
|
+
get message() {
|
|
210
|
+
return `Fly App ${this.name} was not created${this.reason ? `: ${this.reason}` : ""}`;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const toAttrs = (app: FlyApp, fallbackName?: string): App["Attributes"] => {
|
|
215
|
+
const appName = app.name ?? fallbackName ?? "";
|
|
216
|
+
return {
|
|
217
|
+
appId: app.id ?? appName,
|
|
218
|
+
appName,
|
|
219
|
+
internalNumericId: app.internal_numeric_id,
|
|
220
|
+
network: app.network,
|
|
221
|
+
status: app.status,
|
|
222
|
+
orgSlug: app.organization?.slug,
|
|
223
|
+
machineCount: app.machine_count,
|
|
224
|
+
volumeCount: app.volume_count,
|
|
225
|
+
url: `https://${appName}.fly.dev`,
|
|
226
|
+
};
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const resolveAppName = (id: string, name: string | undefined, existing?: string) =>
|
|
230
|
+
Effect.gen(function* () {
|
|
231
|
+
if (name !== undefined) return sanitizeFlyAppName(name);
|
|
232
|
+
if (existing !== undefined) return existing;
|
|
233
|
+
return yield* createFlyAppName(id);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
const getByName = (appName: string) =>
|
|
237
|
+
machines
|
|
238
|
+
.getApp({ app_name: appName })
|
|
239
|
+
.pipe(Effect.catchTag("NotFound", () => Effect.succeed(undefined)));
|
|
240
|
+
|
|
241
|
+
const hasAlchemyMachines = (appName: string) =>
|
|
242
|
+
machines.listMachines({ app_name: appName }).pipe(
|
|
243
|
+
Effect.map((machines) =>
|
|
244
|
+
machines.some((machine) => isAlchemyOwnedMetadata(machine.config?.metadata)),
|
|
245
|
+
),
|
|
246
|
+
Effect.catchTag(["NotFound", "Forbidden"], () => Effect.succeed(false)),
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
const hasAlchemyNamed = (names: Array<string | undefined>) =>
|
|
250
|
+
names.some((name) => matchesAlchemyPhysicalName(name));
|
|
251
|
+
|
|
252
|
+
const hasAlchemyVolumes = (appName: string) =>
|
|
253
|
+
machines.listVolumes({ app_name: appName }).pipe(
|
|
254
|
+
Effect.map((volumes) => hasAlchemyNamed(volumes.map((volume) => volume.name))),
|
|
255
|
+
Effect.catchTag(["NotFound", "Forbidden"], () => Effect.succeed(false)),
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
const hasAlchemySecrets = (appName: string) =>
|
|
259
|
+
machines.listSecrets({ app_name: appName }).pipe(
|
|
260
|
+
Effect.map((res) => hasAlchemyNamed((res.secrets ?? []).map((secret) => secret.name))),
|
|
261
|
+
Effect.catchTag(["NotFound", "Forbidden"], () => Effect.succeed(false)),
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
const hasAlchemySecretKeys = (appName: string) =>
|
|
265
|
+
machines.listSecretKeys({ app_name: appName }).pipe(
|
|
266
|
+
Effect.map((res) => hasAlchemyNamed((res.secret_keys ?? []).map((key) => key.name))),
|
|
267
|
+
Effect.catchTag(["NotFound", "Forbidden"], () => Effect.succeed(false)),
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
const isOwnedApp = (app: FlyApp) =>
|
|
271
|
+
Effect.gen(function* () {
|
|
272
|
+
if (matchesAlchemyPhysicalName(app.name)) return true;
|
|
273
|
+
const appName = app.name;
|
|
274
|
+
if (appName === undefined || appName.length === 0) return false;
|
|
275
|
+
const flags = yield* Effect.all(
|
|
276
|
+
[
|
|
277
|
+
hasAlchemyMachines(appName),
|
|
278
|
+
hasAlchemyVolumes(appName),
|
|
279
|
+
hasAlchemySecrets(appName),
|
|
280
|
+
hasAlchemySecretKeys(appName),
|
|
281
|
+
],
|
|
282
|
+
{ concurrency: 4 },
|
|
283
|
+
);
|
|
284
|
+
return flags.some(Boolean);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Apps in the current token's org that Alchemy owns. Used by {@link App}
|
|
289
|
+
* `list()` and by child resources (Machine / Volume / Secret) so nuke
|
|
290
|
+
* never enumerates the whole org unfiltered.
|
|
291
|
+
*/
|
|
292
|
+
export const listOwnedApps = Effect.fn(function* () {
|
|
293
|
+
const orgSlug = yield* resolveOrgSlug();
|
|
294
|
+
const { apps } = yield* machines.listApps({ org_slug: orgSlug });
|
|
295
|
+
const flagged = yield* Effect.forEach(
|
|
296
|
+
apps ?? [],
|
|
297
|
+
(app) => isOwnedApp(app).pipe(Effect.map((owned) => (owned ? toAttrs(app) : undefined))),
|
|
298
|
+
{ concurrency: 8 },
|
|
299
|
+
);
|
|
300
|
+
return flagged.filter((attrs) => attrs !== undefined);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Observe an App by name and create it when missing. Shared by
|
|
305
|
+
* {@link App} and by Services that own their App.
|
|
306
|
+
*/
|
|
307
|
+
export const ensureApp = Effect.fn(function* (input: {
|
|
308
|
+
name: string;
|
|
309
|
+
orgSlug?: string;
|
|
310
|
+
network?: string;
|
|
311
|
+
enableSubdomains?: boolean;
|
|
312
|
+
/** Physical name from a previous reconcile, observed first. */
|
|
313
|
+
previousName?: string;
|
|
314
|
+
}) {
|
|
315
|
+
let current = input.previousName !== undefined ? yield* getByName(input.previousName) : undefined;
|
|
316
|
+
if (current === undefined && input.previousName !== input.name) {
|
|
317
|
+
current = yield* getByName(input.name);
|
|
318
|
+
}
|
|
319
|
+
if (current === undefined) {
|
|
320
|
+
const orgSlug = input.orgSlug ?? (yield* resolveOrgSlug());
|
|
321
|
+
// A name race surfaces as Conflict or UnprocessableEntity; the lookup
|
|
322
|
+
// decides whether the App now exists. Apps created at the same time on
|
|
323
|
+
// a network that does not exist yet race to create it, and the losers
|
|
324
|
+
// are rejected with "uniqueness constraint violated", so retry them.
|
|
325
|
+
const create = machines
|
|
326
|
+
.createApp({
|
|
327
|
+
name: input.name,
|
|
328
|
+
org_slug: orgSlug,
|
|
329
|
+
network: input.network,
|
|
330
|
+
enable_subdomains: input.enableSubdomains,
|
|
331
|
+
})
|
|
332
|
+
.pipe(
|
|
333
|
+
Effect.as(undefined),
|
|
334
|
+
Effect.catchTag(["Conflict", "UnprocessableEntity"], (error) => Effect.succeed(error)),
|
|
335
|
+
);
|
|
336
|
+
// A new App can take a moment to become readable.
|
|
337
|
+
const observe = getByName(input.name).pipe(
|
|
338
|
+
Effect.repeat({
|
|
339
|
+
schedule: Schedule.spaced("1 second"),
|
|
340
|
+
until: (app) => app !== undefined,
|
|
341
|
+
times: 5,
|
|
342
|
+
}),
|
|
343
|
+
);
|
|
344
|
+
let rejection: string | undefined;
|
|
345
|
+
for (let attempt = 0; attempt < 5 && current === undefined; attempt++) {
|
|
346
|
+
if (attempt > 0) yield* Effect.sleep(`${attempt * 2} seconds`);
|
|
347
|
+
rejection = (yield* create)?.message;
|
|
348
|
+
current = yield* observe;
|
|
349
|
+
}
|
|
350
|
+
if (current === undefined) {
|
|
351
|
+
return yield* new AppNotCreated({ name: input.name, reason: rejection });
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (current === undefined) {
|
|
355
|
+
return yield* new AppNotCreated({ name: input.name });
|
|
356
|
+
}
|
|
357
|
+
return current;
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Delete an App and the Alchemy-owned Volumes in it. Idempotent: a missing
|
|
362
|
+
* App is not an error. Fly deletes the App's Machines, addresses, secrets,
|
|
363
|
+
* and certificates with it.
|
|
364
|
+
*/
|
|
365
|
+
export const deleteApp = Effect.fn(function* (appName: string) {
|
|
366
|
+
if (appName.length === 0) return;
|
|
367
|
+
const volumes = yield* machines
|
|
368
|
+
.listVolumes({ app_name: appName })
|
|
369
|
+
.pipe(Effect.catchTag(["NotFound", "Forbidden"], () => Effect.succeed([])));
|
|
370
|
+
yield* Effect.forEach(
|
|
371
|
+
volumes,
|
|
372
|
+
(volume) => {
|
|
373
|
+
const volumeId = volume.id;
|
|
374
|
+
if (
|
|
375
|
+
volumeId === undefined ||
|
|
376
|
+
volumeId.length === 0 ||
|
|
377
|
+
!matchesAlchemyPhysicalName(volume.name)
|
|
378
|
+
) {
|
|
379
|
+
return Effect.void;
|
|
380
|
+
}
|
|
381
|
+
return machines.deleteVolume({ app_name: appName, volume_id: volumeId }).pipe(
|
|
382
|
+
Effect.asVoid,
|
|
383
|
+
Effect.catchTag(["NotFound", "Conflict"], () => Effect.void),
|
|
384
|
+
);
|
|
385
|
+
},
|
|
386
|
+
{ concurrency: 4 },
|
|
387
|
+
);
|
|
388
|
+
const http = yield* HttpClient.HttpClient;
|
|
389
|
+
const fetchOptions = yield* Effect.serviceOption(FetchHttpClient.RequestInit);
|
|
390
|
+
yield* machines.deleteApp({ app_name: appName }).pipe(
|
|
391
|
+
Retry.none,
|
|
392
|
+
// Bun can replay DELETE on a reused socket below the SDK retry policy.
|
|
393
|
+
Effect.provideService(
|
|
394
|
+
HttpClient.HttpClient,
|
|
395
|
+
HttpClient.mapRequest(http, HttpClientRequest.setHeader("connection", "close")),
|
|
396
|
+
),
|
|
397
|
+
Effect.provideService(FetchHttpClient.RequestInit, {
|
|
398
|
+
...Option.getOrUndefined(fetchOptions),
|
|
399
|
+
keepalive: false,
|
|
400
|
+
redirect: "error",
|
|
401
|
+
}),
|
|
402
|
+
Effect.timeout("30 seconds"),
|
|
403
|
+
Effect.catchTag("NotFound", () => Effect.void),
|
|
404
|
+
Effect.catchTag(
|
|
405
|
+
[
|
|
406
|
+
"HttpClientError",
|
|
407
|
+
"TimeoutError",
|
|
408
|
+
"InternalServerError",
|
|
409
|
+
"BadGateway",
|
|
410
|
+
"ServiceUnavailable",
|
|
411
|
+
"GatewayTimeout",
|
|
412
|
+
],
|
|
413
|
+
(error) => Effect.fail(new AppDeletionAmbiguous({ appName, evidence: error._tag })),
|
|
414
|
+
),
|
|
415
|
+
);
|
|
416
|
+
const gone = yield* getByName(appName).pipe(
|
|
417
|
+
Effect.map((app) => app === undefined),
|
|
418
|
+
Effect.repeat({ schedule: Schedule.spaced("1 second"), until: (gone) => gone, times: 8 }),
|
|
419
|
+
Effect.timeout("30 seconds"),
|
|
420
|
+
Effect.mapError(
|
|
421
|
+
(error) =>
|
|
422
|
+
new AppDeletionAmbiguous({
|
|
423
|
+
appName,
|
|
424
|
+
evidence: `delete accepted but absence verification failed: ${error._tag}`,
|
|
425
|
+
}),
|
|
426
|
+
),
|
|
427
|
+
);
|
|
428
|
+
if (!gone)
|
|
429
|
+
return yield* new AppDeletionAmbiguous({
|
|
430
|
+
appName,
|
|
431
|
+
evidence: "delete accepted but absence not observed",
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
/** Fail when two Services placed in the App publish the same port. */
|
|
436
|
+
const validateServicePorts = (
|
|
437
|
+
appName: string,
|
|
438
|
+
bindings: ReadonlyArray<ResourceBinding<AppBinding> & { action?: string }>,
|
|
439
|
+
) => {
|
|
440
|
+
const conflict = findPortConflict(
|
|
441
|
+
appName,
|
|
442
|
+
bindings
|
|
443
|
+
.filter((binding) => binding.action !== "delete")
|
|
444
|
+
.map((binding) => ({
|
|
445
|
+
id: binding.data.service,
|
|
446
|
+
// A Service in a shared App is public: default ports are 80 and 443.
|
|
447
|
+
ports: withBindingPort(
|
|
448
|
+
portsOfProps(binding.data.services, true),
|
|
449
|
+
binding.data.bindingPort ?? DEFAULT_BINDING_PORT,
|
|
450
|
+
),
|
|
451
|
+
})),
|
|
452
|
+
);
|
|
453
|
+
return conflict === undefined ? Effect.void : Effect.fail(conflict);
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
export const AppProvider = () =>
|
|
457
|
+
Provider.succeed(App, {
|
|
458
|
+
stables: ["appId", "appName", "orgSlug", "network", "internalNumericId"],
|
|
459
|
+
|
|
460
|
+
diff: Effect.fn(function* ({ id, news, output, newBindings }) {
|
|
461
|
+
// At plan time, including for an App created in the same deploy.
|
|
462
|
+
if (isResolved(newBindings)) {
|
|
463
|
+
yield* validateServicePorts(
|
|
464
|
+
output?.appName ?? (isResolved(news) ? news?.name : undefined) ?? id,
|
|
465
|
+
newBindings,
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
if (news === undefined || !isResolved(news)) return undefined;
|
|
469
|
+
if (output === undefined) return undefined;
|
|
470
|
+
const desiredName = news.name !== undefined ? sanitizeFlyAppName(news.name) : output.appName;
|
|
471
|
+
const nameChanged = desiredName !== output.appName;
|
|
472
|
+
const orgChanged = news.orgSlug !== undefined && news.orgSlug !== output.orgSlug;
|
|
473
|
+
const networkChanged = news.network !== undefined && news.network !== output.network;
|
|
474
|
+
if (nameChanged || orgChanged || networkChanged) {
|
|
475
|
+
return {
|
|
476
|
+
action: "replace" as const,
|
|
477
|
+
// Same physical name cannot exist twice — delete the old App first.
|
|
478
|
+
deleteFirst: !nameChanged,
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
return undefined;
|
|
482
|
+
}),
|
|
483
|
+
|
|
484
|
+
read: Effect.fn(function* ({ id, olds, output }) {
|
|
485
|
+
const name = yield* resolveAppName(id, olds?.name, output?.appName);
|
|
486
|
+
const found =
|
|
487
|
+
(output?.appName !== undefined ? yield* getByName(output.appName) : undefined) ??
|
|
488
|
+
(yield* getByName(name));
|
|
489
|
+
if (found === undefined) return undefined;
|
|
490
|
+
const attrs = toAttrs(found, name);
|
|
491
|
+
if (output !== undefined) return attrs;
|
|
492
|
+
return (yield* isOwnedApp(found)) ? attrs : Unowned(attrs);
|
|
493
|
+
}),
|
|
494
|
+
|
|
495
|
+
list: listOwnedApps,
|
|
496
|
+
|
|
497
|
+
reconcile: Effect.fn(function* ({ id, news, output, bindings }) {
|
|
498
|
+
const props = news ?? {};
|
|
499
|
+
const name = yield* resolveAppName(id, props.name, output?.appName);
|
|
500
|
+
// Before creating anything, so a conflict leaves the App untouched.
|
|
501
|
+
yield* validateServicePorts(name, bindings);
|
|
502
|
+
const current = yield* ensureApp({
|
|
503
|
+
name,
|
|
504
|
+
orgSlug: props.orgSlug,
|
|
505
|
+
network: props.network,
|
|
506
|
+
enableSubdomains: props.enableSubdomains,
|
|
507
|
+
previousName: output?.appName,
|
|
508
|
+
});
|
|
509
|
+
// No update API. enableSubdomains is create-only.
|
|
510
|
+
return toAttrs(current, name);
|
|
511
|
+
}),
|
|
512
|
+
|
|
513
|
+
delete: Effect.fn(function* ({ output }) {
|
|
514
|
+
yield* deleteApp(output.appName);
|
|
515
|
+
}),
|
|
516
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { DEFAULT_API_BASE_URL, normalizeApiBaseUrl } from "@distilled.cloud/fly-io";
|
|
2
|
+
import { getEnv, getEnvRedactedRequired } from "alchemy/Auth/Env";
|
|
3
|
+
import {
|
|
4
|
+
makeStoredAuthProvider,
|
|
5
|
+
storedSecret,
|
|
6
|
+
storedValueText,
|
|
7
|
+
type StoredAuthConfig,
|
|
8
|
+
} from "alchemy/Auth/StoredAuthProvider";
|
|
9
|
+
import * as Effect from "effect/Effect";
|
|
10
|
+
import * as Redacted from "effect/Redacted";
|
|
11
|
+
|
|
12
|
+
export const FLY_AUTH_PROVIDER_NAME = "Fly";
|
|
13
|
+
export const FLY_API_TOKEN_ENV = "FLY_API_TOKEN";
|
|
14
|
+
export const FLY_API_HOSTNAME_ENV = "FLY_API_HOSTNAME";
|
|
15
|
+
|
|
16
|
+
export type FlyAuthConfig = StoredAuthConfig;
|
|
17
|
+
|
|
18
|
+
export type FlyResolvedCredentials = {
|
|
19
|
+
type: "token";
|
|
20
|
+
apiKey: Redacted.Redacted<string>;
|
|
21
|
+
apiBaseUrl: string;
|
|
22
|
+
source: { type: FlyAuthConfig["method"] | "env"; details?: string };
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const resolveApiBaseUrl = (explicit?: string) =>
|
|
26
|
+
getEnv(FLY_API_HOSTNAME_ENV).pipe(
|
|
27
|
+
Effect.map((fromEnv) => normalizeApiBaseUrl(explicit ?? fromEnv)),
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const flyAuth = makeStoredAuthProvider<FlyResolvedCredentials>({
|
|
31
|
+
provider: FLY_AUTH_PROVIDER_NAME,
|
|
32
|
+
fields: [
|
|
33
|
+
{ name: "apiKey", label: "Fly.io API Token", secret: true },
|
|
34
|
+
{
|
|
35
|
+
name: "apiBaseUrl",
|
|
36
|
+
label: "Fly API hostname",
|
|
37
|
+
placeholder: DEFAULT_API_BASE_URL,
|
|
38
|
+
optional: true,
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
toResolved: (values) => ({
|
|
42
|
+
type: "token",
|
|
43
|
+
apiKey: storedSecret(values.apiKey) ?? Redacted.make(""),
|
|
44
|
+
apiBaseUrl: normalizeApiBaseUrl(storedValueText(values.apiBaseUrl)),
|
|
45
|
+
source: { type: "stored" },
|
|
46
|
+
}),
|
|
47
|
+
readEnvironment: Effect.gen(function* () {
|
|
48
|
+
const apiKey = yield* getEnvRedactedRequired(FLY_API_TOKEN_ENV);
|
|
49
|
+
const apiBaseUrl = yield* resolveApiBaseUrl();
|
|
50
|
+
return {
|
|
51
|
+
type: "token" as const,
|
|
52
|
+
apiKey,
|
|
53
|
+
apiBaseUrl,
|
|
54
|
+
source: { type: "env" as const, details: FLY_API_TOKEN_ENV },
|
|
55
|
+
};
|
|
56
|
+
}),
|
|
57
|
+
environment: [
|
|
58
|
+
{ name: FLY_API_TOKEN_ENV, required: true, secret: true },
|
|
59
|
+
{ name: FLY_API_HOSTNAME_ENV, required: false },
|
|
60
|
+
],
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Layer that registers the Fly {@link AuthProvider} into the
|
|
65
|
+
* {@link AuthProviders} registry. Fly uses a stored API token locally and
|
|
66
|
+
* `FLY_API_TOKEN` in CI; `FLY_API_HOSTNAME` optionally overrides the API root.
|
|
67
|
+
*/
|
|
68
|
+
export const FlyAuth = flyAuth.layer;
|