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