@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
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import type { VolumeSnapshot as FlyVolumeSnapshot } from "@distilled.cloud/fly-io/machines";
|
|
2
|
+
import * as machines from "@distilled.cloud/fly-io/machines";
|
|
3
|
+
import { isResolved } from "alchemy/Diff";
|
|
4
|
+
import * as Provider from "alchemy/Provider";
|
|
5
|
+
import { Resource } from "alchemy/Resource";
|
|
6
|
+
import * as Data from "effect/Data";
|
|
7
|
+
import * as Duration from "effect/Duration";
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import * as Schedule from "effect/Schedule";
|
|
10
|
+
import type { App } from "./App.ts";
|
|
11
|
+
import type { Providers } from "./Providers.ts";
|
|
12
|
+
import { listOwnedVolumes } from "./Volume.ts";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A resource-valued prop: the resource itself, or an Effect that produces
|
|
16
|
+
* it (so `yield* App(...)` and `App(...)` both type-check).
|
|
17
|
+
*/
|
|
18
|
+
type Ref<T> = T | Effect.Effect<T, never, Providers>;
|
|
19
|
+
|
|
20
|
+
export interface VolumeSnapshotProps {
|
|
21
|
+
/**
|
|
22
|
+
* Parent Fly App. Changing it replaces the snapshot (a new snapshot is
|
|
23
|
+
* created on the new App's Volume). There is no delete API for the old
|
|
24
|
+
* snapshot — it follows Volume `snapshot_retention`.
|
|
25
|
+
*/
|
|
26
|
+
app: Ref<App>;
|
|
27
|
+
/**
|
|
28
|
+
* Fly Volume id to snapshot (`vol_…`). Changing it replaces the
|
|
29
|
+
* snapshot. Identity is the snapshot `id` returned by a subsequent
|
|
30
|
+
* `listVolumeSnapshots`.
|
|
31
|
+
*/
|
|
32
|
+
volumeId: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type VolumeSnapshot = Resource<
|
|
36
|
+
"Fly.VolumeSnapshot",
|
|
37
|
+
VolumeSnapshotProps,
|
|
38
|
+
{
|
|
39
|
+
/** Parent Fly App name. */
|
|
40
|
+
appName: string;
|
|
41
|
+
/** Fly Volume id this snapshot belongs to. */
|
|
42
|
+
volumeId: string;
|
|
43
|
+
/** Fly snapshot id (`vs_…`). Identity of the resource. */
|
|
44
|
+
snapshotId: string;
|
|
45
|
+
/** Observed snapshot status, if the API returned one. */
|
|
46
|
+
status: string | undefined;
|
|
47
|
+
/** Content digest of the snapshot. */
|
|
48
|
+
digest: string | undefined;
|
|
49
|
+
/** Snapshot size in bytes, if the API returned one. */
|
|
50
|
+
size: number | undefined;
|
|
51
|
+
/** Source volume size in GB at snapshot time. */
|
|
52
|
+
volumeSize: number | undefined;
|
|
53
|
+
/** Retention in days. */
|
|
54
|
+
retentionDays: number | undefined;
|
|
55
|
+
/** RFC3339 creation timestamp. */
|
|
56
|
+
createdAt: string | undefined;
|
|
57
|
+
},
|
|
58
|
+
never,
|
|
59
|
+
Providers
|
|
60
|
+
>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* A Fly.VolumeSnapshot is an on-demand snapshot of a mounted disk.
|
|
64
|
+
*
|
|
65
|
+
* Create is fire-and-forget. Identity is the snapshot id from a
|
|
66
|
+
* subsequent list. Destroy is a no-op. Snapshots follow Volume
|
|
67
|
+
* retention. `nuke` skips this type.
|
|
68
|
+
*
|
|
69
|
+
* @see https://fly.io/docs/machines/api/volumes-resource/
|
|
70
|
+
*
|
|
71
|
+
* ### Create a snapshot
|
|
72
|
+
* Point it at a Volume id from the parent {@link Machine} or
|
|
73
|
+
* {@link Service} (`mounts[0].volumeId`).
|
|
74
|
+
*
|
|
75
|
+
* **Example:** Snapshot a mounted disk
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const box = yield* Fly.Machine("Box", {
|
|
78
|
+
* app: Site,
|
|
79
|
+
* region: "iad",
|
|
80
|
+
* image: "nginx:alpine",
|
|
81
|
+
* mounts: [{ path: "/data", sizeGb: 1 }],
|
|
82
|
+
* });
|
|
83
|
+
*
|
|
84
|
+
* export const Nightly = Fly.VolumeSnapshot("Nightly", {
|
|
85
|
+
* app: Site,
|
|
86
|
+
* volumeId: box.mounts[0].volumeId,
|
|
87
|
+
* });
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* :::caution[Changing `app` or `volumeId` replaces the snapshot]
|
|
91
|
+
* A new snapshot is created. There is no delete API for the old one.
|
|
92
|
+
* It follows Volume `snapshot_retention`.
|
|
93
|
+
* :::
|
|
94
|
+
*
|
|
95
|
+
* ### Restore
|
|
96
|
+
* Restore into a new disk with `snapshotId` on the mount. Create-only.
|
|
97
|
+
* The new Machine gets a copy. The original Volume is unchanged.
|
|
98
|
+
*
|
|
99
|
+
* **Example:** Restore onto a Machine
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const restored = yield* Fly.Machine("Restored", {
|
|
102
|
+
* app: Site,
|
|
103
|
+
* region: "iad",
|
|
104
|
+
* image: "nginx:alpine",
|
|
105
|
+
* mounts: [{ path: "/data", sizeGb: 1, snapshotId: Nightly.snapshotId }],
|
|
106
|
+
* });
|
|
107
|
+
* ```
|
|
108
|
+
*
|
|
109
|
+
* ### Restore into a Service
|
|
110
|
+
* Pass `snapshotId` on {@link MountVolume}. Same create-only rule.
|
|
111
|
+
*
|
|
112
|
+
* **Example:** Restore onto a Service
|
|
113
|
+
* ```typescript
|
|
114
|
+
* export default class Api extends Fly.Service<Api>()(
|
|
115
|
+
* "Api",
|
|
116
|
+
* { app: Site, main: import.meta.url, region: "iad", port: 3000 },
|
|
117
|
+
* Effect.gen(function* () {
|
|
118
|
+
* const disk = yield* Fly.MountVolume({
|
|
119
|
+
* path: "/data",
|
|
120
|
+
* sizeGb: 1,
|
|
121
|
+
* snapshotId: Nightly.snapshotId,
|
|
122
|
+
* });
|
|
123
|
+
* return {
|
|
124
|
+
* fetch: Effect.succeed(HttpServerResponse.text(disk.path)),
|
|
125
|
+
* };
|
|
126
|
+
* }).pipe(Effect.provide(Fly.MountVolumeLive)),
|
|
127
|
+
* ) {}
|
|
128
|
+
* ```
|
|
129
|
+
*
|
|
130
|
+
* @resource
|
|
131
|
+
* @product Volume
|
|
132
|
+
*/
|
|
133
|
+
export const VolumeSnapshot = Resource<VolumeSnapshot>("Fly.VolumeSnapshot");
|
|
134
|
+
|
|
135
|
+
export class VolumeSnapshotNotCreated extends Data.TaggedError("Fly.VolumeSnapshotNotCreated")<{
|
|
136
|
+
appName: string;
|
|
137
|
+
volumeId: string;
|
|
138
|
+
}> {}
|
|
139
|
+
|
|
140
|
+
export class VolumeSnapshotRefsMissing extends Data.TaggedError("Fly.VolumeSnapshotRefsMissing")<{
|
|
141
|
+
message: string;
|
|
142
|
+
}> {}
|
|
143
|
+
|
|
144
|
+
class VolumeSnapshotPending extends Data.TaggedError("Fly.VolumeSnapshotPending")<{
|
|
145
|
+
volumeId: string;
|
|
146
|
+
}> {}
|
|
147
|
+
|
|
148
|
+
const backoff = Schedule.min([
|
|
149
|
+
Schedule.exponential(Duration.millis(500), 1.5),
|
|
150
|
+
Schedule.spaced(Duration.seconds(5)),
|
|
151
|
+
]);
|
|
152
|
+
|
|
153
|
+
const appNameOf = (value: unknown): string | undefined => {
|
|
154
|
+
if (value == null || typeof value !== "object") return undefined;
|
|
155
|
+
const name = (value as { appName?: unknown }).appName;
|
|
156
|
+
return typeof name === "string" && name.length > 0 ? name : undefined;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const volumeIdOf = (value: unknown): string | undefined => {
|
|
160
|
+
if (typeof value === "string" && value.length > 0) return value;
|
|
161
|
+
if (value == null || typeof value !== "object") return undefined;
|
|
162
|
+
const id = (value as { volumeId?: unknown }).volumeId;
|
|
163
|
+
return typeof id === "string" && id.length > 0 ? id : undefined;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const toAttrs = (
|
|
167
|
+
appName: string,
|
|
168
|
+
volumeId: string,
|
|
169
|
+
snapshot: FlyVolumeSnapshot,
|
|
170
|
+
): VolumeSnapshot["Attributes"] => ({
|
|
171
|
+
appName,
|
|
172
|
+
volumeId,
|
|
173
|
+
snapshotId: snapshot.id ?? "",
|
|
174
|
+
status: snapshot.status,
|
|
175
|
+
digest: snapshot.digest,
|
|
176
|
+
size: snapshot.size,
|
|
177
|
+
volumeSize: snapshot.volume_size,
|
|
178
|
+
retentionDays: snapshot.retention_days,
|
|
179
|
+
createdAt: snapshot.created_at,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const listSnapshots = (appName: string, volumeId: string) =>
|
|
183
|
+
machines
|
|
184
|
+
.listVolumeSnapshots({
|
|
185
|
+
app_name: appName,
|
|
186
|
+
volume_id: volumeId,
|
|
187
|
+
})
|
|
188
|
+
.pipe(
|
|
189
|
+
Effect.catchTag(["NotFound", "Forbidden"], () => Effect.succeed([] as FlyVolumeSnapshot[])),
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
const findById = (appName: string, volumeId: string, snapshotId: string) =>
|
|
193
|
+
listSnapshots(appName, volumeId).pipe(
|
|
194
|
+
Effect.map((snapshots) => snapshots.find((snapshot) => snapshot.id === snapshotId)),
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
const newestFirst = (left: FlyVolumeSnapshot, right: FlyVolumeSnapshot) =>
|
|
198
|
+
Date.parse(right.created_at ?? "") - Date.parse(left.created_at ?? "");
|
|
199
|
+
|
|
200
|
+
const pickNewest = (snapshots: FlyVolumeSnapshot[]): FlyVolumeSnapshot | undefined =>
|
|
201
|
+
snapshots.filter((snapshot) => (snapshot.id ?? "").length > 0).sort(newestFirst)[0];
|
|
202
|
+
|
|
203
|
+
const waitForNewSnapshot = (appName: string, volumeId: string, knownIds: ReadonlySet<string>) =>
|
|
204
|
+
listSnapshots(appName, volumeId).pipe(
|
|
205
|
+
Effect.flatMap((snapshots) => {
|
|
206
|
+
const next = pickNewest(
|
|
207
|
+
snapshots.filter((snapshot) => snapshot.id !== undefined && !knownIds.has(snapshot.id)),
|
|
208
|
+
);
|
|
209
|
+
if (next !== undefined) return Effect.succeed(next);
|
|
210
|
+
return Effect.fail(new VolumeSnapshotPending({ volumeId }));
|
|
211
|
+
}),
|
|
212
|
+
Effect.retry({
|
|
213
|
+
while: (e) => e._tag === "Fly.VolumeSnapshotPending",
|
|
214
|
+
times: 8,
|
|
215
|
+
schedule: backoff,
|
|
216
|
+
}),
|
|
217
|
+
Effect.catchTag("Fly.VolumeSnapshotPending", () => Effect.undefined),
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
export const VolumeSnapshotProvider = () =>
|
|
221
|
+
Provider.succeed(VolumeSnapshot, {
|
|
222
|
+
stables: ["snapshotId", "volumeId", "appName"],
|
|
223
|
+
nuke: { skip: true },
|
|
224
|
+
|
|
225
|
+
diff: Effect.fn(function* ({ news, output }) {
|
|
226
|
+
if (news === undefined || !isResolved(news)) return undefined;
|
|
227
|
+
if (output === undefined) return undefined;
|
|
228
|
+
const desiredApp = appNameOf(news.app);
|
|
229
|
+
const appChanged = desiredApp !== undefined && desiredApp !== output.appName;
|
|
230
|
+
const desiredVolume = volumeIdOf(news.volumeId);
|
|
231
|
+
const volumeChanged = desiredVolume !== undefined && desiredVolume !== output.volumeId;
|
|
232
|
+
if (appChanged || volumeChanged) {
|
|
233
|
+
return { action: "replace" as const };
|
|
234
|
+
}
|
|
235
|
+
return undefined;
|
|
236
|
+
}),
|
|
237
|
+
|
|
238
|
+
read: Effect.fn(function* ({ olds, output }) {
|
|
239
|
+
const appName = output?.appName ?? appNameOf(olds?.app);
|
|
240
|
+
const volumeId = output?.volumeId ?? volumeIdOf(olds?.volumeId);
|
|
241
|
+
if (appName === undefined || volumeId === undefined) return undefined;
|
|
242
|
+
const snapshotId = output?.snapshotId;
|
|
243
|
+
if (snapshotId === undefined || snapshotId.length === 0) {
|
|
244
|
+
return undefined;
|
|
245
|
+
}
|
|
246
|
+
const found = yield* findById(appName, volumeId, snapshotId);
|
|
247
|
+
if (found === undefined) return undefined;
|
|
248
|
+
return toAttrs(appName, volumeId, found);
|
|
249
|
+
}),
|
|
250
|
+
|
|
251
|
+
list: Effect.fn(function* () {
|
|
252
|
+
const volumes = yield* listOwnedVolumes();
|
|
253
|
+
const groups = yield* Effect.forEach(
|
|
254
|
+
volumes,
|
|
255
|
+
({ appName, volumeId }) =>
|
|
256
|
+
listSnapshots(appName, volumeId).pipe(
|
|
257
|
+
Effect.map((snapshots) =>
|
|
258
|
+
snapshots
|
|
259
|
+
.filter((snapshot) => snapshot.id !== undefined && snapshot.id.length > 0)
|
|
260
|
+
.map((snapshot) => toAttrs(appName, volumeId, snapshot)),
|
|
261
|
+
),
|
|
262
|
+
),
|
|
263
|
+
{ concurrency: 8 },
|
|
264
|
+
);
|
|
265
|
+
return groups.flat();
|
|
266
|
+
}),
|
|
267
|
+
|
|
268
|
+
reconcile: Effect.fn(function* ({ news, output }) {
|
|
269
|
+
const props = news ?? ({} as VolumeSnapshotProps);
|
|
270
|
+
const appName = appNameOf(props.app) ?? output?.appName;
|
|
271
|
+
const volumeId = volumeIdOf(props.volumeId) ?? output?.volumeId;
|
|
272
|
+
if (appName === undefined || volumeId === undefined) {
|
|
273
|
+
return yield* new VolumeSnapshotRefsMissing({
|
|
274
|
+
message: "Fly.VolumeSnapshot requires a resolved App with appName and a volumeId.",
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Observe by cached snapshot id on the target volume.
|
|
279
|
+
const observed = yield* listSnapshots(appName, volumeId);
|
|
280
|
+
let current =
|
|
281
|
+
output?.snapshotId !== undefined && output.snapshotId.length > 0
|
|
282
|
+
? observed.find((snapshot) => snapshot.id === output.snapshotId)
|
|
283
|
+
: undefined;
|
|
284
|
+
|
|
285
|
+
if (current === undefined) {
|
|
286
|
+
const knownIds = new Set(
|
|
287
|
+
observed.flatMap((snapshot) =>
|
|
288
|
+
snapshot.id !== undefined && snapshot.id.length > 0 ? [snapshot.id] : [],
|
|
289
|
+
),
|
|
290
|
+
);
|
|
291
|
+
yield* machines
|
|
292
|
+
.createVolumeSnapshot({
|
|
293
|
+
app_name: appName,
|
|
294
|
+
volume_id: volumeId,
|
|
295
|
+
})
|
|
296
|
+
.pipe(
|
|
297
|
+
Effect.asVoid,
|
|
298
|
+
Effect.catchTag("Conflict", () => Effect.void),
|
|
299
|
+
Effect.retry({
|
|
300
|
+
while: (e) =>
|
|
301
|
+
e._tag === "NotFound" ||
|
|
302
|
+
(e._tag === "BadRequest" && e.message.includes("uninitialized volume")),
|
|
303
|
+
times: 8,
|
|
304
|
+
schedule: backoff,
|
|
305
|
+
}),
|
|
306
|
+
);
|
|
307
|
+
current = yield* waitForNewSnapshot(appName, volumeId, knownIds);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (current === undefined || current.id === undefined) {
|
|
311
|
+
return yield* new VolumeSnapshotNotCreated({ appName, volumeId });
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return toAttrs(appName, volumeId, current);
|
|
315
|
+
}),
|
|
316
|
+
|
|
317
|
+
delete: Effect.fn(function* () {
|
|
318
|
+
// Fly has no snapshot delete API. Snapshots expire with Volume
|
|
319
|
+
// snapshot_retention or when the Volume is deleted.
|
|
320
|
+
}),
|
|
321
|
+
});
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { Credentials, fromCredentials } from "@distilled.cloud/aws/Credentials";
|
|
3
|
+
import * as AwsEndpoint from "@distilled.cloud/aws/Endpoint";
|
|
4
|
+
import type { RegionName } from "@distilled.cloud/aws/Region";
|
|
5
|
+
import * as s3 from "@distilled.cloud/aws/s3";
|
|
6
|
+
import * as Provider from "alchemy/Provider";
|
|
7
|
+
import { Resource } from "alchemy/Resource";
|
|
8
|
+
import { initialCwd } from "alchemy/Util/Node";
|
|
9
|
+
import { cacheControlOf, contentTypeOf } from "alchemy/Website/assets";
|
|
10
|
+
import * as Effect from "effect/Effect";
|
|
11
|
+
import * as FileSystem from "effect/FileSystem";
|
|
12
|
+
import * as FetchHttpClient from "effect/http/FetchHttpClient";
|
|
13
|
+
import type * as HttpClient from "effect/http/HttpClient";
|
|
14
|
+
import * as Layer from "effect/Layer";
|
|
15
|
+
import * as Path from "effect/Path";
|
|
16
|
+
import * as Redacted from "effect/Redacted";
|
|
17
|
+
import * as Stream from "effect/Stream";
|
|
18
|
+
import type { Bucket } from "../Bucket.ts";
|
|
19
|
+
import { TigrisCredentialsMissing } from "../Errors.ts";
|
|
20
|
+
import type { Providers } from "../Providers.ts";
|
|
21
|
+
|
|
22
|
+
const s3Concurrency = 16;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Unwrap Tigris {@link Bucket} attrs for the S3 client. Credentials and
|
|
26
|
+
* the endpoint are `Redacted<string>`; names are plain strings. This is
|
|
27
|
+
* Fly Bucket plumbing, not website MIME — it stays here because this
|
|
28
|
+
* resource is the only Website helper that speaks Tigris.
|
|
29
|
+
*/
|
|
30
|
+
const asPlain = (value: unknown): string | undefined => {
|
|
31
|
+
if (typeof value === "string" && value.length > 0) return value;
|
|
32
|
+
if (Redacted.isRedacted(value)) {
|
|
33
|
+
const inner = Redacted.value(value);
|
|
34
|
+
return typeof inner === "string" && inner.length > 0 ? inner : undefined;
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export interface AssetDeploymentProps {
|
|
40
|
+
/**
|
|
41
|
+
* Destination Tigris bucket (a {@link Bucket} resource).
|
|
42
|
+
*/
|
|
43
|
+
bucket: Bucket;
|
|
44
|
+
/**
|
|
45
|
+
* Local directory to upload (framework `clientDirectory`).
|
|
46
|
+
*/
|
|
47
|
+
sourcePath: string;
|
|
48
|
+
/**
|
|
49
|
+
* Optional key prefix within the bucket.
|
|
50
|
+
*/
|
|
51
|
+
prefix?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Delete observed keys under the prefix that are not in this deploy.
|
|
54
|
+
* @default true
|
|
55
|
+
*/
|
|
56
|
+
purge?: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface AssetDeployment extends Resource<
|
|
60
|
+
"Fly.Website.AssetDeployment",
|
|
61
|
+
AssetDeploymentProps,
|
|
62
|
+
{
|
|
63
|
+
bucketName: string;
|
|
64
|
+
prefix: string;
|
|
65
|
+
version: string;
|
|
66
|
+
fileCount: number;
|
|
67
|
+
files: string[];
|
|
68
|
+
},
|
|
69
|
+
never,
|
|
70
|
+
Providers
|
|
71
|
+
> {}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Upload a local directory into a public Tigris bucket for Fly Website
|
|
75
|
+
* statics. HTML is never cached; everything else is immutable.
|
|
76
|
+
*
|
|
77
|
+
* @resource
|
|
78
|
+
*/
|
|
79
|
+
export const AssetDeployment = Resource<AssetDeployment>("Fly.Website.AssetDeployment");
|
|
80
|
+
|
|
81
|
+
const normalizePrefix = (prefix: string | undefined) =>
|
|
82
|
+
prefix ? prefix.replace(/^\/+|\/+$/g, "") : "";
|
|
83
|
+
|
|
84
|
+
const scopeOf = (bucket: Bucket) =>
|
|
85
|
+
Effect.gen(function* () {
|
|
86
|
+
const bucketName = asPlain(bucket.bucketName) ?? asPlain(bucket.name);
|
|
87
|
+
const accessKeyId = asPlain(bucket.accessKeyId);
|
|
88
|
+
const secretAccessKey = asPlain(bucket.secretAccessKey);
|
|
89
|
+
const endpoint = asPlain(bucket.endpoint);
|
|
90
|
+
const region = (asPlain(bucket.region) ?? "auto") as RegionName;
|
|
91
|
+
if (
|
|
92
|
+
bucketName === undefined ||
|
|
93
|
+
accessKeyId === undefined ||
|
|
94
|
+
secretAccessKey === undefined ||
|
|
95
|
+
endpoint === undefined
|
|
96
|
+
) {
|
|
97
|
+
return yield* new TigrisCredentialsMissing({
|
|
98
|
+
resourceName: bucketName ?? bucket.LogicalId,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return { bucketName, accessKeyId, secretAccessKey, endpoint, region };
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const withTigris = <A, E>(
|
|
105
|
+
scope: {
|
|
106
|
+
accessKeyId: string;
|
|
107
|
+
secretAccessKey: string;
|
|
108
|
+
endpoint: string;
|
|
109
|
+
region: RegionName;
|
|
110
|
+
},
|
|
111
|
+
operation: Effect.Effect<A, E, Credentials | HttpClient.HttpClient>,
|
|
112
|
+
) =>
|
|
113
|
+
operation.pipe(
|
|
114
|
+
Effect.provide(
|
|
115
|
+
Layer.mergeAll(
|
|
116
|
+
fromCredentials(
|
|
117
|
+
{
|
|
118
|
+
accessKeyId: Redacted.make(scope.accessKeyId),
|
|
119
|
+
secretAccessKey: Redacted.make(scope.secretAccessKey),
|
|
120
|
+
},
|
|
121
|
+
scope.region,
|
|
122
|
+
),
|
|
123
|
+
AwsEndpoint.of(scope.endpoint),
|
|
124
|
+
FetchHttpClient.layer,
|
|
125
|
+
),
|
|
126
|
+
),
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const walkFiles = Effect.fn(function* (root: string) {
|
|
130
|
+
const fs = yield* FileSystem.FileSystem;
|
|
131
|
+
const path = yield* Path.Path;
|
|
132
|
+
if (!(yield* fs.exists(root))) return [] as string[];
|
|
133
|
+
const names = yield* fs.readDirectory(root, { recursive: true });
|
|
134
|
+
const files = yield* Effect.forEach(
|
|
135
|
+
names,
|
|
136
|
+
(name) =>
|
|
137
|
+
Effect.gen(function* () {
|
|
138
|
+
const full = path.join(root, name);
|
|
139
|
+
const stat = yield* fs.stat(full);
|
|
140
|
+
return stat.type === "File" ? name.replaceAll("\\", "/") : undefined;
|
|
141
|
+
}),
|
|
142
|
+
{ concurrency: "unbounded" },
|
|
143
|
+
);
|
|
144
|
+
return files
|
|
145
|
+
.filter((name): name is string => name !== undefined)
|
|
146
|
+
.sort((a, b) => a.localeCompare(b));
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const listObserved = (
|
|
150
|
+
scope: {
|
|
151
|
+
bucketName: string;
|
|
152
|
+
accessKeyId: string;
|
|
153
|
+
secretAccessKey: string;
|
|
154
|
+
endpoint: string;
|
|
155
|
+
region: RegionName;
|
|
156
|
+
},
|
|
157
|
+
prefix: string,
|
|
158
|
+
) =>
|
|
159
|
+
withTigris(
|
|
160
|
+
scope,
|
|
161
|
+
s3.listObjectsV2
|
|
162
|
+
.pages({
|
|
163
|
+
Bucket: scope.bucketName,
|
|
164
|
+
Prefix: prefix.length > 0 ? `${prefix}/` : undefined,
|
|
165
|
+
})
|
|
166
|
+
.pipe(
|
|
167
|
+
Stream.flatMap((page) => Stream.fromIterable(page.Contents ?? [])),
|
|
168
|
+
Stream.runFold(
|
|
169
|
+
() => new Map<string, string | undefined>(),
|
|
170
|
+
(observed, object) => {
|
|
171
|
+
if (object.Key !== undefined) {
|
|
172
|
+
observed.set(object.Key, object.ETag);
|
|
173
|
+
}
|
|
174
|
+
return observed;
|
|
175
|
+
},
|
|
176
|
+
),
|
|
177
|
+
),
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
const deleteObject = (
|
|
181
|
+
scope: {
|
|
182
|
+
bucketName: string;
|
|
183
|
+
accessKeyId: string;
|
|
184
|
+
secretAccessKey: string;
|
|
185
|
+
endpoint: string;
|
|
186
|
+
region: RegionName;
|
|
187
|
+
},
|
|
188
|
+
key: string,
|
|
189
|
+
) =>
|
|
190
|
+
withTigris(
|
|
191
|
+
scope,
|
|
192
|
+
s3.deleteObject({
|
|
193
|
+
Bucket: scope.bucketName,
|
|
194
|
+
Key: key,
|
|
195
|
+
}),
|
|
196
|
+
).pipe(Effect.catchTag("NoSuchKey", () => Effect.void));
|
|
197
|
+
|
|
198
|
+
export const AssetDeploymentProvider = () =>
|
|
199
|
+
Provider.effect(
|
|
200
|
+
AssetDeployment,
|
|
201
|
+
Effect.succeed({
|
|
202
|
+
list: () => Effect.succeed([]),
|
|
203
|
+
read: Effect.fn(function* ({ output }) {
|
|
204
|
+
return output;
|
|
205
|
+
}),
|
|
206
|
+
reconcile: Effect.fn(function* ({ news, session }) {
|
|
207
|
+
const fs = yield* FileSystem.FileSystem;
|
|
208
|
+
const path = yield* Path.Path;
|
|
209
|
+
const scope = yield* scopeOf(news.bucket);
|
|
210
|
+
const prefix = normalizePrefix(news.prefix);
|
|
211
|
+
const root = path.isAbsolute(news.sourcePath)
|
|
212
|
+
? news.sourcePath
|
|
213
|
+
: path.resolve(initialCwd, news.sourcePath);
|
|
214
|
+
const files = yield* walkFiles(root);
|
|
215
|
+
const observed = yield* listObserved(scope, prefix);
|
|
216
|
+
const prepared = yield* Effect.forEach(
|
|
217
|
+
files,
|
|
218
|
+
(relative) =>
|
|
219
|
+
Effect.gen(function* () {
|
|
220
|
+
const body = yield* fs.readFile(path.join(root, relative));
|
|
221
|
+
const key = prefix.length > 0 ? `${prefix}/${relative}` : relative;
|
|
222
|
+
const contentType = contentTypeOf(relative);
|
|
223
|
+
const cacheControl = cacheControlOf(relative);
|
|
224
|
+
return { relative, key, body, contentType, cacheControl };
|
|
225
|
+
}),
|
|
226
|
+
{ concurrency: "unbounded" },
|
|
227
|
+
);
|
|
228
|
+
const version = yield* Effect.sync(() => {
|
|
229
|
+
const hash = createHash("sha256");
|
|
230
|
+
for (const file of prepared) {
|
|
231
|
+
hash.update(file.relative);
|
|
232
|
+
hash.update(file.body);
|
|
233
|
+
hash.update(file.contentType);
|
|
234
|
+
hash.update(file.cacheControl);
|
|
235
|
+
}
|
|
236
|
+
return hash.digest("hex");
|
|
237
|
+
});
|
|
238
|
+
const desired = new Set(prepared.map((file) => file.key));
|
|
239
|
+
yield* Effect.all(
|
|
240
|
+
prepared.flatMap((file) => {
|
|
241
|
+
const expected = createHash("md5").update(file.body).digest("hex");
|
|
242
|
+
const etag = observed.get(file.key)?.replace(/^"|"$/g, "");
|
|
243
|
+
if (etag === expected) return [];
|
|
244
|
+
return [
|
|
245
|
+
withTigris(
|
|
246
|
+
scope,
|
|
247
|
+
s3.putObject({
|
|
248
|
+
Bucket: scope.bucketName,
|
|
249
|
+
Key: file.key,
|
|
250
|
+
Body: file.body,
|
|
251
|
+
ContentType: file.contentType,
|
|
252
|
+
CacheControl: file.cacheControl,
|
|
253
|
+
}),
|
|
254
|
+
),
|
|
255
|
+
];
|
|
256
|
+
}),
|
|
257
|
+
{ concurrency: s3Concurrency },
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
if (news.purge ?? true) {
|
|
261
|
+
yield* Effect.forEach(
|
|
262
|
+
[...observed.keys()].filter((key) => !desired.has(key)),
|
|
263
|
+
(key) => deleteObject(scope, key),
|
|
264
|
+
{ concurrency: s3Concurrency },
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const output = {
|
|
269
|
+
bucketName: scope.bucketName,
|
|
270
|
+
prefix,
|
|
271
|
+
version,
|
|
272
|
+
fileCount: files.length,
|
|
273
|
+
files: prepared.map((file) => file.relative),
|
|
274
|
+
};
|
|
275
|
+
yield* session.note(
|
|
276
|
+
`Uploaded ${output.fileCount} file(s) to tigris://${output.bucketName}/${output.prefix}`,
|
|
277
|
+
);
|
|
278
|
+
return output;
|
|
279
|
+
}),
|
|
280
|
+
delete: Effect.fn(
|
|
281
|
+
function* ({ olds, output }) {
|
|
282
|
+
if (!(olds.purge ?? true)) return;
|
|
283
|
+
const scope = yield* scopeOf(olds.bucket);
|
|
284
|
+
const observed = yield* listObserved(scope, output.prefix);
|
|
285
|
+
yield* Effect.forEach([...observed.keys()], (key) => deleteObject(scope, key), {
|
|
286
|
+
concurrency: s3Concurrency,
|
|
287
|
+
});
|
|
288
|
+
},
|
|
289
|
+
Effect.catchTag("NoSuchBucket", () => Effect.void),
|
|
290
|
+
),
|
|
291
|
+
}),
|
|
292
|
+
);
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { resolveAstroOutput } from "alchemy/Website/AstroOutput";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import { frameworkSite, staticConfigFromAssets, type FrameworkSiteProps } from "./FrameworkSite.ts";
|
|
4
|
+
|
|
5
|
+
/** The framework-integration package that drives the Astro build. */
|
|
6
|
+
export const ASTRO_FRAMEWORK_SPECIFIER = "@alchemy.run/frontend-frameworks/astro";
|
|
7
|
+
|
|
8
|
+
/** The Node container deploy target for the Astro build. */
|
|
9
|
+
export const ASTRO_NODE_TARGET_SPECIFIER = "@alchemy.run/frontend-frameworks/astro/node";
|
|
10
|
+
|
|
11
|
+
export interface AstroProps extends FrameworkSiteProps {
|
|
12
|
+
/**
|
|
13
|
+
* Serializable Astro config merged OVER the project's own
|
|
14
|
+
* `astro.config.*` (which loads natively). `adapter` is owned by the Node
|
|
15
|
+
* deploy target and may not be set here.
|
|
16
|
+
*/
|
|
17
|
+
astro?: {
|
|
18
|
+
/** The full URL the site deploys to (`Astro.site`). */
|
|
19
|
+
site?: string;
|
|
20
|
+
/** Base path the site deploys under. */
|
|
21
|
+
base?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Astro output target. `"server"` renders pages on demand; individual
|
|
24
|
+
* pages opt into prerendering with `export const prerender = true`.
|
|
25
|
+
* `"static"` prerenders every page at build time and deploys
|
|
26
|
+
* assets-only (no SSR server). Overrides the `output` in your
|
|
27
|
+
* `astro.config.*`; leave it unset to use the file's value.
|
|
28
|
+
* @default the config file's `output`, else `"server"`
|
|
29
|
+
*/
|
|
30
|
+
output?: "server" | "static";
|
|
31
|
+
/** Source directory, relative to `rootDir`. @default "./src" */
|
|
32
|
+
srcDir?: string;
|
|
33
|
+
/** Public (static passthrough) directory. @default "./public" */
|
|
34
|
+
publicDir?: string;
|
|
35
|
+
/** Build output directory. @default "./dist" */
|
|
36
|
+
outDir?: string;
|
|
37
|
+
/** Trailing-slash handling for routes. */
|
|
38
|
+
trailingSlash?: "always" | "never" | "ignore";
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Deploy an [Astro](https://astro.build) application to Fly: a Service
|
|
44
|
+
* running the Node adapter's serve entry (static files first, then the
|
|
45
|
+
* framework handler) on port 3000.
|
|
46
|
+
*
|
|
47
|
+
* Pages render on demand by default (`output: "server"`). When your
|
|
48
|
+
* `astro.config.*` or `astro: { output: "static" }` declares a static
|
|
49
|
+
* site, every page is prerendered and the deploy is assets-only.
|
|
50
|
+
*
|
|
51
|
+
*
|
|
52
|
+
* ### Creating Astro Sites
|
|
53
|
+
* **Example:** Basic Astro App
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const site = yield* Fly.Website.Astro("Web", {
|
|
56
|
+
* rootDir: "./app",
|
|
57
|
+
* });
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* **Example:** Custom Domain
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const site = yield* Fly.Website.Astro("Web", {
|
|
63
|
+
* rootDir: "./app",
|
|
64
|
+
* domain: "app.example.com",
|
|
65
|
+
* });
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* ### Static Sites
|
|
69
|
+
* **Example:** Fully Static Astro Site
|
|
70
|
+
* ```typescript
|
|
71
|
+
* const site = yield* Fly.Website.Astro("Docs", {
|
|
72
|
+
* rootDir: "./docs",
|
|
73
|
+
* astro: { output: "static" },
|
|
74
|
+
* assets: { notFoundHandling: "404-page" },
|
|
75
|
+
* });
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @resource
|
|
79
|
+
* @product Website
|
|
80
|
+
*/
|
|
81
|
+
export const Astro = (id: string, props: AstroProps = {}) =>
|
|
82
|
+
resolveAstroOutput({ rootDir: props.rootDir, output: props.astro?.output }).pipe(
|
|
83
|
+
Effect.flatMap((output) =>
|
|
84
|
+
frameworkSite(id, props, {
|
|
85
|
+
name: "Astro",
|
|
86
|
+
framework: ASTRO_FRAMEWORK_SPECIFIER,
|
|
87
|
+
target: ASTRO_NODE_TARGET_SPECIFIER,
|
|
88
|
+
options: { astro: { ...props.astro, output } },
|
|
89
|
+
static: output === "static" ? staticConfigFromAssets(props.assets) : undefined,
|
|
90
|
+
}),
|
|
91
|
+
),
|
|
92
|
+
);
|