alchemy 2.0.0-beta.34 → 2.0.0-beta.36
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/bin/cli.js +8 -7
- package/bin/exec.js +253 -52
- package/bin/exec.js.map +1 -1
- package/lib/AWS/AuthProvider.d.ts +7 -6
- package/lib/AWS/AuthProvider.d.ts.map +1 -1
- package/lib/AWS/AuthProvider.js +143 -134
- package/lib/AWS/AuthProvider.js.map +1 -1
- package/lib/AWS/Bootstrap.d.ts +2 -2
- package/lib/AWS/Bootstrap.d.ts.map +1 -1
- package/lib/AWS/EC2/hosted.d.ts +1 -1
- package/lib/AWS/Environment.d.ts +25 -3
- package/lib/AWS/Environment.d.ts.map +1 -1
- package/lib/AWS/Environment.js +47 -3
- package/lib/AWS/Environment.js.map +1 -1
- package/lib/AWS/IAM/OpenIDConnectProvider.d.ts +14 -6
- package/lib/AWS/IAM/OpenIDConnectProvider.d.ts.map +1 -1
- package/lib/AWS/IAM/OpenIDConnectProvider.js +6 -3
- package/lib/AWS/IAM/OpenIDConnectProvider.js.map +1 -1
- package/lib/AWS/IAM/Policy.d.ts +1 -1
- package/lib/AWS/IAM/Policy.d.ts.map +1 -1
- package/lib/AWS/IAM/Policy.js.map +1 -1
- package/lib/AWS/Lambda/BucketEventSource.d.ts +1 -1
- package/lib/AWS/Lambda/BucketEventSource.d.ts.map +1 -1
- package/lib/AWS/Lambda/EventBridgeEventSource.d.ts +1 -1
- package/lib/AWS/Lambda/EventBridgeEventSource.d.ts.map +1 -1
- package/lib/AWS/Lambda/QueueEventSource.d.ts +1 -1
- package/lib/AWS/Lambda/QueueEventSource.d.ts.map +1 -1
- package/lib/AWS/Lambda/StreamEventSource.d.ts +1 -1
- package/lib/AWS/Lambda/StreamEventSource.d.ts.map +1 -1
- package/lib/AWS/Lambda/TableEventSource.d.ts +1 -1
- package/lib/AWS/Lambda/TableEventSource.d.ts.map +1 -1
- package/lib/AWS/Lambda/TopicEventSource.d.ts +1 -1
- package/lib/AWS/Lambda/TopicEventSource.d.ts.map +1 -1
- package/lib/AWS/Providers.d.ts +1 -1
- package/lib/AWS/Providers.d.ts.map +1 -1
- package/lib/AWS/Providers.js +2 -1
- package/lib/AWS/Providers.js.map +1 -1
- package/lib/Auth/Credentials.d.ts +21 -6
- package/lib/Auth/Credentials.d.ts.map +1 -1
- package/lib/Auth/Credentials.js +30 -31
- package/lib/Auth/Credentials.js.map +1 -1
- package/lib/Auth/Profile.d.ts +31 -34
- package/lib/Auth/Profile.d.ts.map +1 -1
- package/lib/Auth/Profile.js +46 -31
- package/lib/Auth/Profile.js.map +1 -1
- package/lib/Axiom/AuthProvider.d.ts +2 -1
- package/lib/Axiom/AuthProvider.d.ts.map +1 -1
- package/lib/Axiom/AuthProvider.js +149 -143
- package/lib/Axiom/AuthProvider.js.map +1 -1
- package/lib/Axiom/Credentials.d.ts +2 -1
- package/lib/Axiom/Credentials.d.ts.map +1 -1
- package/lib/Axiom/Credentials.js +4 -4
- package/lib/Axiom/Credentials.js.map +1 -1
- package/lib/Axiom/Providers.d.ts +1 -1
- package/lib/Axiom/Providers.d.ts.map +1 -1
- package/lib/Axiom/Providers.js +3 -1
- package/lib/Axiom/Providers.js.map +1 -1
- package/lib/Cli/LoggingCli.d.ts.map +1 -1
- package/lib/Cli/LoggingCli.js +105 -7
- package/lib/Cli/LoggingCli.js.map +1 -1
- package/lib/Cli/checkVersion.d.ts +13 -0
- package/lib/Cli/checkVersion.d.ts.map +1 -0
- package/lib/Cli/checkVersion.js +47 -0
- package/lib/Cli/checkVersion.js.map +1 -0
- package/lib/Cli/commands/_shared.d.ts +2 -2
- package/lib/Cli/commands/_shared.d.ts.map +1 -1
- package/lib/Cli/commands/_shared.js +3 -3
- package/lib/Cli/commands/_shared.js.map +1 -1
- package/lib/Cli/commands/aws.d.ts +6 -0
- package/lib/Cli/commands/aws.d.ts.map +1 -0
- package/lib/Cli/commands/aws.js +63 -0
- package/lib/Cli/commands/aws.js.map +1 -0
- package/lib/Cli/commands/cloudflare.d.ts +17 -0
- package/lib/Cli/commands/cloudflare.d.ts.map +1 -0
- package/lib/Cli/commands/cloudflare.js +111 -0
- package/lib/Cli/commands/cloudflare.js.map +1 -0
- package/lib/Cli/commands/deploy.d.ts +6 -5
- package/lib/Cli/commands/deploy.d.ts.map +1 -1
- package/lib/Cli/commands/deploy.js +10 -10
- package/lib/Cli/commands/deploy.js.map +1 -1
- package/lib/Cli/commands/dev.d.ts.map +1 -1
- package/lib/Cli/commands/dev.js +16 -16
- package/lib/Cli/commands/dev.js.map +1 -1
- package/lib/Cli/commands/login.d.ts +2 -1
- package/lib/Cli/commands/login.d.ts.map +1 -1
- package/lib/Cli/commands/login.js +9 -8
- package/lib/Cli/commands/login.js.map +1 -1
- package/lib/Cli/commands/logs.d.ts +1 -1
- package/lib/Cli/commands/logs.d.ts.map +1 -1
- package/lib/Cli/commands/logs.js +7 -7
- package/lib/Cli/commands/logs.js.map +1 -1
- package/lib/Cli/commands/profile.d.ts +3 -1
- package/lib/Cli/commands/profile.d.ts.map +1 -1
- package/lib/Cli/commands/profile.js +14 -11
- package/lib/Cli/commands/profile.js.map +1 -1
- package/lib/Cli/commands/state.d.ts +1 -1
- package/lib/Cli/commands/state.d.ts.map +1 -1
- package/lib/Cli/commands/state.js +8 -8
- package/lib/Cli/commands/state.js.map +1 -1
- package/lib/Cli/commands/tail.d.ts +1 -1
- package/lib/Cli/commands/tail.d.ts.map +1 -1
- package/lib/Cli/commands/tail.js +7 -7
- package/lib/Cli/commands/tail.js.map +1 -1
- package/lib/Cli/exec.d.ts.map +1 -1
- package/lib/Cli/exec.js +5 -3
- package/lib/Cli/exec.js.map +1 -1
- package/lib/Cli/main.d.ts.map +1 -1
- package/lib/Cli/main.js +19 -5
- package/lib/Cli/main.js.map +1 -1
- package/lib/Cli/selectCli.d.ts +12 -0
- package/lib/Cli/selectCli.d.ts.map +1 -0
- package/lib/Cli/selectCli.js +32 -0
- package/lib/Cli/selectCli.js.map +1 -0
- package/lib/Cloudflare/Auth/AuthProvider.d.ts +2 -1
- package/lib/Cloudflare/Auth/AuthProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Auth/AuthProvider.js +235 -214
- package/lib/Cloudflare/Auth/AuthProvider.js.map +1 -1
- package/lib/Cloudflare/CloudflareEnvironment.d.ts +2 -1
- package/lib/Cloudflare/CloudflareEnvironment.d.ts.map +1 -1
- package/lib/Cloudflare/CloudflareEnvironment.js +3 -2
- package/lib/Cloudflare/CloudflareEnvironment.js.map +1 -1
- package/lib/Cloudflare/Credentials.d.ts +2 -1
- package/lib/Cloudflare/Credentials.d.ts.map +1 -1
- package/lib/Cloudflare/Credentials.js +4 -4
- package/lib/Cloudflare/Credentials.js.map +1 -1
- package/lib/Cloudflare/D1/D1Clone.d.ts +2 -1
- package/lib/Cloudflare/D1/D1Clone.d.ts.map +1 -1
- package/lib/Cloudflare/D1/D1Database.d.ts +2 -1
- package/lib/Cloudflare/D1/D1Database.d.ts.map +1 -1
- package/lib/Cloudflare/D1/D1Import.d.ts +3 -1
- package/lib/Cloudflare/D1/D1Import.d.ts.map +1 -1
- package/lib/Cloudflare/Images/Images.d.ts +103 -0
- package/lib/Cloudflare/Images/Images.d.ts.map +1 -0
- package/lib/Cloudflare/Images/Images.js +82 -0
- package/lib/Cloudflare/Images/Images.js.map +1 -0
- package/lib/Cloudflare/Images/ImagesBinding.d.ts +73 -0
- package/lib/Cloudflare/Images/ImagesBinding.d.ts.map +1 -0
- package/lib/Cloudflare/Images/ImagesBinding.js +83 -0
- package/lib/Cloudflare/Images/ImagesBinding.js.map +1 -0
- package/lib/Cloudflare/Images/index.d.ts +3 -0
- package/lib/Cloudflare/Images/index.d.ts.map +1 -0
- package/lib/Cloudflare/Images/index.js +3 -0
- package/lib/Cloudflare/Images/index.js.map +1 -0
- package/lib/Cloudflare/Local/Sidecar.d.ts +11 -4
- package/lib/Cloudflare/Local/Sidecar.d.ts.map +1 -1
- package/lib/Cloudflare/Local/Sidecar.js +8 -6
- package/lib/Cloudflare/Local/Sidecar.js.map +1 -1
- package/lib/Cloudflare/Local/SidecarHandlers.d.ts.map +1 -1
- package/lib/Cloudflare/Local/SidecarHandlers.js +1 -5
- package/lib/Cloudflare/Local/SidecarHandlers.js.map +1 -1
- package/lib/Cloudflare/Local/SidecarServer.js +5 -2
- package/lib/Cloudflare/Local/SidecarServer.js.map +1 -1
- package/lib/Cloudflare/Logs.d.ts +5 -0
- package/lib/Cloudflare/Logs.d.ts.map +1 -1
- package/lib/Cloudflare/Logs.js +70 -1
- package/lib/Cloudflare/Logs.js.map +1 -1
- package/lib/Cloudflare/Providers.d.ts +1 -1
- package/lib/Cloudflare/Providers.d.ts.map +1 -1
- package/lib/Cloudflare/Providers.js +6 -1
- package/lib/Cloudflare/Providers.js.map +1 -1
- package/lib/Cloudflare/Queue/Queue.d.ts +1 -1
- package/lib/Cloudflare/Queue/Queue.js +1 -1
- package/lib/Cloudflare/Queue/QueueConsumer.d.ts +6 -2
- package/lib/Cloudflare/Queue/QueueConsumer.d.ts.map +1 -1
- package/lib/Cloudflare/Queue/QueueConsumer.js +194 -53
- package/lib/Cloudflare/Queue/QueueConsumer.js.map +1 -1
- package/lib/Cloudflare/Queue/QueueEventSource.d.ts +106 -0
- package/lib/Cloudflare/Queue/QueueEventSource.d.ts.map +1 -0
- package/lib/Cloudflare/Queue/QueueEventSource.js +145 -0
- package/lib/Cloudflare/Queue/QueueEventSource.js.map +1 -0
- package/lib/Cloudflare/Queue/index.d.ts +1 -0
- package/lib/Cloudflare/Queue/index.d.ts.map +1 -1
- package/lib/Cloudflare/Queue/index.js +1 -0
- package/lib/Cloudflare/Queue/index.js.map +1 -1
- package/lib/Cloudflare/R2/R2Bucket.d.ts +229 -0
- package/lib/Cloudflare/R2/R2Bucket.d.ts.map +1 -1
- package/lib/Cloudflare/R2/R2Bucket.js +309 -2
- package/lib/Cloudflare/R2/R2Bucket.js.map +1 -1
- package/lib/Cloudflare/StateStore/State.d.ts +4 -3
- package/lib/Cloudflare/StateStore/State.d.ts.map +1 -1
- package/lib/Cloudflare/StateStore/State.js +16 -8
- package/lib/Cloudflare/StateStore/State.js.map +1 -1
- package/lib/Cloudflare/VpcService/VpcServiceRef.d.ts +1 -1
- package/lib/Cloudflare/VpcService/VpcServiceRef.d.ts.map +1 -1
- package/lib/Cloudflare/Website/StaticSite.d.ts.map +1 -1
- package/lib/Cloudflare/Website/StaticSite.js +10 -1
- package/lib/Cloudflare/Website/StaticSite.js.map +1 -1
- package/lib/Cloudflare/Workers/Assets.d.ts +1 -1
- package/lib/Cloudflare/Workers/Assets.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/InferEnv.d.ts +1 -1
- package/lib/Cloudflare/Workers/InferEnv.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js +11 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js.map +1 -1
- package/lib/Cloudflare/Workers/Worker.d.ts +14 -12
- package/lib/Cloudflare/Workers/Worker.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Worker.js +96 -165
- package/lib/Cloudflare/Workers/Worker.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBundle.d.ts +2 -0
- package/lib/Cloudflare/Workers/WorkerBundle.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBundle.js +21 -7
- package/lib/Cloudflare/Workers/WorkerBundle.js.map +1 -1
- package/lib/Cloudflare/Zone.d.ts +14 -0
- package/lib/Cloudflare/Zone.d.ts.map +1 -0
- package/lib/Cloudflare/Zone.js +44 -0
- package/lib/Cloudflare/Zone.js.map +1 -0
- package/lib/Cloudflare/index.d.ts +1 -0
- package/lib/Cloudflare/index.d.ts.map +1 -1
- package/lib/Cloudflare/index.js +1 -0
- package/lib/Cloudflare/index.js.map +1 -1
- package/lib/Drizzle/Schema.d.ts.map +1 -1
- package/lib/Drizzle/Schema.js +20 -5
- package/lib/Drizzle/Schema.js.map +1 -1
- package/lib/GitHub/AuthProvider.d.ts +3 -1
- package/lib/GitHub/AuthProvider.d.ts.map +1 -1
- package/lib/GitHub/AuthProvider.js +114 -108
- package/lib/GitHub/AuthProvider.js.map +1 -1
- package/lib/GitHub/Credentials.d.ts +2 -1
- package/lib/GitHub/Credentials.d.ts.map +1 -1
- package/lib/GitHub/Credentials.js +4 -4
- package/lib/GitHub/Credentials.js.map +1 -1
- package/lib/GitHub/Providers.d.ts +1 -1
- package/lib/GitHub/Providers.d.ts.map +1 -1
- package/lib/GitHub/Providers.js +3 -1
- package/lib/GitHub/Providers.js.map +1 -1
- package/lib/GitHub/Secrets.d.ts.map +1 -1
- package/lib/GitHub/Secrets.js +14 -1
- package/lib/GitHub/Secrets.js.map +1 -1
- package/lib/GitHub/Variables.d.ts +40 -0
- package/lib/GitHub/Variables.d.ts.map +1 -0
- package/lib/GitHub/Variables.js +28 -0
- package/lib/GitHub/Variables.js.map +1 -0
- package/lib/GitHub/index.d.ts +1 -0
- package/lib/GitHub/index.d.ts.map +1 -1
- package/lib/GitHub/index.js +1 -0
- package/lib/GitHub/index.js.map +1 -1
- package/lib/Neon/AuthProvider.d.ts +3 -1
- package/lib/Neon/AuthProvider.d.ts.map +1 -1
- package/lib/Neon/AuthProvider.js +87 -80
- package/lib/Neon/AuthProvider.js.map +1 -1
- package/lib/Neon/Credentials.d.ts +2 -1
- package/lib/Neon/Credentials.d.ts.map +1 -1
- package/lib/Neon/Credentials.js +4 -4
- package/lib/Neon/Credentials.js.map +1 -1
- package/lib/Neon/NeonEnvironment.d.ts +2 -1
- package/lib/Neon/NeonEnvironment.d.ts.map +1 -1
- package/lib/Neon/NeonEnvironment.js +3 -2
- package/lib/Neon/NeonEnvironment.js.map +1 -1
- package/lib/Neon/Project.d.ts +16 -0
- package/lib/Neon/Project.d.ts.map +1 -1
- package/lib/Neon/Project.js +25 -0
- package/lib/Neon/Project.js.map +1 -1
- package/lib/Neon/Providers.d.ts +1 -1
- package/lib/Neon/Providers.d.ts.map +1 -1
- package/lib/Neon/Providers.js +3 -1
- package/lib/Neon/Providers.js.map +1 -1
- package/lib/Neon/api.d.ts +1 -0
- package/lib/Neon/api.d.ts.map +1 -1
- package/lib/Neon/api.js +1 -0
- package/lib/Neon/api.js.map +1 -1
- package/lib/Sidecar/RpcClient.d.ts.map +1 -1
- package/lib/Sidecar/RpcClient.js +8 -5
- package/lib/Sidecar/RpcClient.js.map +1 -1
- package/lib/Sidecar/RpcPaths.d.ts +5 -0
- package/lib/Sidecar/RpcPaths.d.ts.map +1 -1
- package/lib/Sidecar/RpcPaths.js +10 -1
- package/lib/Sidecar/RpcPaths.js.map +1 -1
- package/lib/Sidecar/RpcServer.d.ts +24 -4
- package/lib/Sidecar/RpcServer.d.ts.map +1 -1
- package/lib/Sidecar/RpcServer.js +70 -15
- package/lib/Sidecar/RpcServer.js.map +1 -1
- package/lib/Sidecar/RpcServerBun.d.ts +4 -0
- package/lib/Sidecar/RpcServerBun.d.ts.map +1 -0
- package/lib/Sidecar/RpcServerBun.js +28 -0
- package/lib/Sidecar/RpcServerBun.js.map +1 -0
- package/lib/Sidecar/RpcServerNode.d.ts +4 -0
- package/lib/Sidecar/RpcServerNode.d.ts.map +1 -0
- package/lib/Sidecar/RpcServerNode.js +39 -0
- package/lib/Sidecar/RpcServerNode.js.map +1 -0
- package/lib/Sidecar/RpcServices.d.ts +6 -0
- package/lib/Sidecar/RpcServices.d.ts.map +1 -0
- package/lib/Sidecar/RpcServices.js +29 -0
- package/lib/Sidecar/RpcServices.js.map +1 -0
- package/lib/Stack.d.ts +5 -3
- package/lib/Stack.d.ts.map +1 -1
- package/lib/Stack.js +3 -1
- package/lib/Stack.js.map +1 -1
- package/lib/Test/Core.d.ts.map +1 -1
- package/lib/Test/Core.js +5 -4
- package/lib/Test/Core.js.map +1 -1
- package/lib/Test/Vitest.d.ts.map +1 -1
- package/lib/Test/Vitest.js +2 -0
- package/lib/Test/Vitest.js.map +1 -1
- package/lib/Util/LocalhostDns.d.ts +19 -0
- package/lib/Util/LocalhostDns.d.ts.map +1 -0
- package/lib/Util/LocalhostDns.js +55 -0
- package/lib/Util/LocalhostDns.js.map +1 -0
- package/lib/Util/PlatformServices.d.ts.map +1 -1
- package/lib/Util/PlatformServices.js +3 -1
- package/lib/Util/PlatformServices.js.map +1 -1
- package/lib/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +16 -12
- package/src/AWS/AuthProvider.ts +269 -259
- package/src/AWS/Environment.ts +57 -3
- package/src/AWS/IAM/OpenIDConnectProvider.ts +19 -8
- package/src/AWS/IAM/Policy.ts +1 -1
- package/src/AWS/Providers.ts +2 -0
- package/src/Auth/Credentials.ts +82 -46
- package/src/Auth/Profile.ts +123 -69
- package/src/Axiom/AuthProvider.ts +263 -255
- package/src/Axiom/Credentials.ts +3 -4
- package/src/Axiom/Providers.ts +4 -0
- package/src/Cli/LoggingCli.ts +127 -11
- package/src/Cli/checkVersion.ts +57 -0
- package/src/Cli/commands/_shared.ts +4 -4
- package/src/Cli/commands/aws.ts +127 -0
- package/src/Cli/commands/cloudflare.ts +222 -0
- package/src/Cli/commands/deploy.ts +11 -10
- package/src/Cli/commands/dev.ts +28 -33
- package/src/Cli/commands/login.ts +9 -12
- package/src/Cli/commands/logs.ts +8 -8
- package/src/Cli/commands/profile.ts +14 -16
- package/src/Cli/commands/state.ts +8 -8
- package/src/Cli/commands/tail.ts +8 -8
- package/src/Cli/exec.ts +7 -3
- package/src/Cli/main.ts +23 -5
- package/src/Cli/selectCli.ts +33 -0
- package/src/Cloudflare/Auth/AuthProvider.ts +445 -430
- package/src/Cloudflare/CloudflareEnvironment.ts +3 -2
- package/src/Cloudflare/Credentials.ts +3 -4
- package/src/Cloudflare/Images/Images.ts +121 -0
- package/src/Cloudflare/Images/ImagesBinding.ts +192 -0
- package/src/Cloudflare/Images/index.ts +2 -0
- package/src/Cloudflare/Local/Sidecar.ts +13 -10
- package/src/Cloudflare/Local/SidecarHandlers.ts +8 -13
- package/src/Cloudflare/Local/SidecarServer.ts +6 -1
- package/src/Cloudflare/Logs.ts +115 -1
- package/src/Cloudflare/Providers.ts +9 -0
- package/src/Cloudflare/Queue/Queue.ts +1 -1
- package/src/Cloudflare/Queue/QueueConsumer.ts +262 -60
- package/src/Cloudflare/Queue/QueueEventSource.ts +234 -0
- package/src/Cloudflare/Queue/index.ts +1 -0
- package/src/Cloudflare/R2/R2Bucket.ts +570 -2
- package/src/Cloudflare/StateStore/State.ts +25 -16
- package/src/Cloudflare/Website/StaticSite.ts +11 -1
- package/src/Cloudflare/Workers/InferEnv.ts +7 -3
- package/src/Cloudflare/Workers/LocalWorkerProvider.ts +9 -1
- package/src/Cloudflare/Workers/Worker.ts +130 -231
- package/src/Cloudflare/Workers/WorkerBundle.ts +38 -12
- package/src/Cloudflare/Zone.ts +88 -0
- package/src/Cloudflare/index.ts +1 -0
- package/src/Drizzle/Schema.ts +21 -5
- package/src/GitHub/AuthProvider.ts +221 -217
- package/src/GitHub/Credentials.ts +3 -4
- package/src/GitHub/Providers.ts +4 -0
- package/src/GitHub/Secrets.ts +25 -1
- package/src/GitHub/Variables.ts +54 -0
- package/src/GitHub/index.ts +1 -0
- package/src/Neon/AuthProvider.ts +160 -154
- package/src/Neon/Credentials.ts +3 -4
- package/src/Neon/NeonEnvironment.ts +3 -2
- package/src/Neon/Project.ts +42 -0
- package/src/Neon/Providers.ts +4 -0
- package/src/Neon/api.ts +2 -0
- package/src/Sidecar/RpcClient.ts +8 -7
- package/src/Sidecar/RpcPaths.ts +11 -1
- package/src/Sidecar/RpcServer.ts +97 -24
- package/src/Sidecar/RpcServerBun.ts +41 -0
- package/src/Sidecar/RpcServerNode.ts +51 -0
- package/src/Sidecar/RpcServices.ts +48 -0
- package/src/Stack.ts +8 -0
- package/src/Test/Core.ts +10 -4
- package/src/Test/Vitest.ts +3 -0
- package/src/Util/LocalhostDns.ts +58 -0
- package/src/Util/PlatformServices.ts +3 -1
- package/lib/Cli/commands/bootstrap.d.ts +0 -20
- package/lib/Cli/commands/bootstrap.d.ts.map +0 -1
- package/lib/Cli/commands/bootstrap.js +0 -107
- package/lib/Cli/commands/bootstrap.js.map +0 -1
- package/lib/Sidecar/RpcTransport.d.ts +0 -22
- package/lib/Sidecar/RpcTransport.d.ts.map +0 -1
- package/lib/Sidecar/RpcTransport.js +0 -81
- package/lib/Sidecar/RpcTransport.js.map +0 -1
- package/lib/Test/TestCli.d.ts +0 -19
- package/lib/Test/TestCli.d.ts.map +0 -1
- package/lib/Test/TestCli.js +0 -175
- package/lib/Test/TestCli.js.map +0 -1
- package/src/Cli/commands/bootstrap.ts +0 -216
- package/src/Sidecar/RpcTransport.ts +0 -85
- package/src/Test/TestCli.ts +0 -221
|
@@ -1,16 +1,101 @@
|
|
|
1
1
|
import * as r2 from "@distilled.cloud/cloudflare/r2";
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Schedule from "effect/Schedule";
|
|
3
4
|
|
|
4
|
-
import { isResolved } from "../../Diff.ts";
|
|
5
|
+
import { deepEqual, isResolved } from "../../Diff.ts";
|
|
5
6
|
import { createPhysicalName } from "../../PhysicalName.ts";
|
|
6
7
|
import * as Provider from "../../Provider.ts";
|
|
7
8
|
import { Resource } from "../../Resource.ts";
|
|
8
9
|
import { CloudflareEnvironment } from "../CloudflareEnvironment.ts";
|
|
9
10
|
import type * as Cloudflare from "../Providers.ts";
|
|
11
|
+
import * as Zone from "../Zone.ts";
|
|
10
12
|
import { R2BucketBinding } from "./R2BucketBinding.ts";
|
|
11
13
|
|
|
12
14
|
export type R2BucketName = string;
|
|
13
15
|
|
|
16
|
+
export type R2BucketCustomDomainZone = Zone.ZoneReference;
|
|
17
|
+
|
|
18
|
+
export type R2BucketCustomDomain = {
|
|
19
|
+
/**
|
|
20
|
+
* Custom domain name to attach to the bucket.
|
|
21
|
+
*/
|
|
22
|
+
name: string;
|
|
23
|
+
/**
|
|
24
|
+
* Zone that contains the custom domain. If omitted, the zone is inferred
|
|
25
|
+
* from `domain`. Pass a zone ID string, a hostname in the zone, or any object
|
|
26
|
+
* with a `zoneId` attribute such as `Cloudflare.Zone`.
|
|
27
|
+
*/
|
|
28
|
+
zone?: R2BucketCustomDomainZone;
|
|
29
|
+
/**
|
|
30
|
+
* Whether public bucket access is enabled at this custom domain.
|
|
31
|
+
* @default true
|
|
32
|
+
*/
|
|
33
|
+
enabled?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Allowlist of TLS ciphers in BoringSSL format.
|
|
36
|
+
*/
|
|
37
|
+
ciphers?: string[];
|
|
38
|
+
/**
|
|
39
|
+
* Minimum TLS version accepted by the custom domain.
|
|
40
|
+
* @default "1.0"
|
|
41
|
+
*/
|
|
42
|
+
minTLS?: "1.0" | "1.1" | "1.2" | "1.3";
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type R2BucketLifecycleCondition =
|
|
46
|
+
| {
|
|
47
|
+
type: "Age";
|
|
48
|
+
/**
|
|
49
|
+
* Maximum age of an object, in seconds, before the rule's action applies.
|
|
50
|
+
*/
|
|
51
|
+
maxAge: number;
|
|
52
|
+
}
|
|
53
|
+
| {
|
|
54
|
+
type: "Date";
|
|
55
|
+
/**
|
|
56
|
+
* Absolute date (ISO 8601) at which the rule's action applies.
|
|
57
|
+
*/
|
|
58
|
+
date: string;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export type R2BucketLifecycleRule = {
|
|
62
|
+
/**
|
|
63
|
+
* Unique identifier for the rule within the bucket.
|
|
64
|
+
*/
|
|
65
|
+
id: string;
|
|
66
|
+
/**
|
|
67
|
+
* Whether the rule is enabled.
|
|
68
|
+
* @default true
|
|
69
|
+
*/
|
|
70
|
+
enabled?: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Object key prefix the rule applies to. Use `""` (or omit) to match all
|
|
73
|
+
* objects in the bucket.
|
|
74
|
+
* @default ""
|
|
75
|
+
*/
|
|
76
|
+
prefix?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Abort incomplete multipart uploads after the configured age.
|
|
79
|
+
*/
|
|
80
|
+
abortMultipartUploadsTransition?: {
|
|
81
|
+
condition?: { type: "Age"; maxAge: number };
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Delete matching objects after the configured age or on a specific date.
|
|
85
|
+
*/
|
|
86
|
+
deleteObjectsTransition?: {
|
|
87
|
+
condition?: R2BucketLifecycleCondition;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Transition matching objects to a different storage class. Cloudflare R2
|
|
91
|
+
* only supports transitioning to `InfrequentAccess` today.
|
|
92
|
+
*/
|
|
93
|
+
storageClassTransitions?: {
|
|
94
|
+
condition: R2BucketLifecycleCondition;
|
|
95
|
+
storageClass: "InfrequentAccess";
|
|
96
|
+
}[];
|
|
97
|
+
};
|
|
98
|
+
|
|
14
99
|
export type R2BucketProps = {
|
|
15
100
|
/**
|
|
16
101
|
* Name of the bucket. If omitted, a unique name will be generated.
|
|
@@ -31,6 +116,17 @@ export type R2BucketProps = {
|
|
|
31
116
|
* Location hint for the bucket.
|
|
32
117
|
*/
|
|
33
118
|
locationHint?: R2Bucket.Location;
|
|
119
|
+
/**
|
|
120
|
+
* Custom domains to attach to the bucket. Pass an empty array (or omit)
|
|
121
|
+
* to remove all custom domains.
|
|
122
|
+
*/
|
|
123
|
+
domains?: R2BucketCustomDomain[];
|
|
124
|
+
/**
|
|
125
|
+
* Object lifecycle rules applied to the bucket. Pass an empty array (or
|
|
126
|
+
* omit) to clear all lifecycle rules. See the Cloudflare R2 docs for
|
|
127
|
+
* supported transitions.
|
|
128
|
+
*/
|
|
129
|
+
lifecycleRules?: R2BucketLifecycleRule[];
|
|
34
130
|
};
|
|
35
131
|
|
|
36
132
|
export type R2Bucket = Resource<
|
|
@@ -42,6 +138,8 @@ export type R2Bucket = Resource<
|
|
|
42
138
|
jurisdiction: R2Bucket.Jurisdiction;
|
|
43
139
|
location: R2Bucket.Location | undefined;
|
|
44
140
|
accountId: string;
|
|
141
|
+
domains: R2Bucket.CustomDomain[];
|
|
142
|
+
lifecycleRules: R2Bucket.LifecycleRule[];
|
|
45
143
|
},
|
|
46
144
|
never,
|
|
47
145
|
Cloudflare.Providers
|
|
@@ -89,6 +187,112 @@ export type R2Bucket = Resource<
|
|
|
89
187
|
* contentLength: Number(request.headers["content-length"] ?? 0),
|
|
90
188
|
* });
|
|
91
189
|
* ```
|
|
190
|
+
*
|
|
191
|
+
* @section Custom Domains
|
|
192
|
+
*
|
|
193
|
+
* Attach one or more custom domains to serve bucket objects from a hostname
|
|
194
|
+
* you control. The domain's zone must already exist in your Cloudflare
|
|
195
|
+
* account; the zone is inferred from the hostname when omitted, or you can
|
|
196
|
+
* pass a `Cloudflare.Zone` resource, a zone ID, or any hostname inside the
|
|
197
|
+
* zone via the `zone` field.
|
|
198
|
+
*
|
|
199
|
+
* @example Single custom domain
|
|
200
|
+
* ```typescript
|
|
201
|
+
* const bucket = yield* Cloudflare.R2Bucket("MyBucket", {
|
|
202
|
+
* domains: [{ name: "assets.example.com" }],
|
|
203
|
+
* });
|
|
204
|
+
* ```
|
|
205
|
+
*
|
|
206
|
+
* @example Multiple custom domains
|
|
207
|
+
* ```typescript
|
|
208
|
+
* const bucket = yield* Cloudflare.R2Bucket("MyBucket", {
|
|
209
|
+
* domains: [
|
|
210
|
+
* { name: "assets.example.com" },
|
|
211
|
+
* { name: "static.example.com" },
|
|
212
|
+
* ],
|
|
213
|
+
* });
|
|
214
|
+
* ```
|
|
215
|
+
*
|
|
216
|
+
* @example Disable a custom domain without removing it
|
|
217
|
+
* ```typescript
|
|
218
|
+
* const bucket = yield* Cloudflare.R2Bucket("MyBucket", {
|
|
219
|
+
* domains: [{ name: "assets.example.com", enabled: false }],
|
|
220
|
+
* });
|
|
221
|
+
* ```
|
|
222
|
+
*
|
|
223
|
+
* @example Custom domain with explicit zone and TLS settings
|
|
224
|
+
* ```typescript
|
|
225
|
+
* const zone = yield* Cloudflare.Zone("ExampleZone", {
|
|
226
|
+
* name: "example.com",
|
|
227
|
+
* });
|
|
228
|
+
*
|
|
229
|
+
* const bucket = yield* Cloudflare.R2Bucket("MyBucket", {
|
|
230
|
+
* domains: [
|
|
231
|
+
* {
|
|
232
|
+
* name: "assets.example.com",
|
|
233
|
+
* zone,
|
|
234
|
+
* minTLS: "1.2",
|
|
235
|
+
* },
|
|
236
|
+
* ],
|
|
237
|
+
* });
|
|
238
|
+
* ```
|
|
239
|
+
*
|
|
240
|
+
* @section Object Lifecycle Rules
|
|
241
|
+
*
|
|
242
|
+
* Configure lifecycle rules to automatically delete objects, abort
|
|
243
|
+
* incomplete multipart uploads, or transition objects to InfrequentAccess
|
|
244
|
+
* storage. Pass an empty array (or omit) to clear all rules. See the
|
|
245
|
+
* [Cloudflare R2 docs](https://developers.cloudflare.com/r2/buckets/object-lifecycles/)
|
|
246
|
+
* for details and limits (max 1000 rules per bucket).
|
|
247
|
+
*
|
|
248
|
+
* @example Delete objects 30 days after upload
|
|
249
|
+
* ```typescript
|
|
250
|
+
* const bucket = yield* Cloudflare.R2Bucket("MyBucket", {
|
|
251
|
+
* lifecycleRules: [
|
|
252
|
+
* {
|
|
253
|
+
* id: "expire-old-objects",
|
|
254
|
+
* deleteObjectsTransition: {
|
|
255
|
+
* condition: { type: "Age", maxAge: 60 * 60 * 24 * 30 },
|
|
256
|
+
* },
|
|
257
|
+
* },
|
|
258
|
+
* ],
|
|
259
|
+
* });
|
|
260
|
+
* ```
|
|
261
|
+
*
|
|
262
|
+
* @example Transition to InfrequentAccess after 60 days, delete after 365
|
|
263
|
+
* ```typescript
|
|
264
|
+
* const bucket = yield* Cloudflare.R2Bucket("MyBucket", {
|
|
265
|
+
* lifecycleRules: [
|
|
266
|
+
* {
|
|
267
|
+
* id: "archive-then-delete",
|
|
268
|
+
* prefix: "logs/",
|
|
269
|
+
* storageClassTransitions: [
|
|
270
|
+
* {
|
|
271
|
+
* condition: { type: "Age", maxAge: 60 * 60 * 24 * 60 },
|
|
272
|
+
* storageClass: "InfrequentAccess",
|
|
273
|
+
* },
|
|
274
|
+
* ],
|
|
275
|
+
* deleteObjectsTransition: {
|
|
276
|
+
* condition: { type: "Age", maxAge: 60 * 60 * 24 * 365 },
|
|
277
|
+
* },
|
|
278
|
+
* },
|
|
279
|
+
* ],
|
|
280
|
+
* });
|
|
281
|
+
* ```
|
|
282
|
+
*
|
|
283
|
+
* @example Abort incomplete multipart uploads after 7 days
|
|
284
|
+
* ```typescript
|
|
285
|
+
* const bucket = yield* Cloudflare.R2Bucket("MyBucket", {
|
|
286
|
+
* lifecycleRules: [
|
|
287
|
+
* {
|
|
288
|
+
* id: "abort-stale-uploads",
|
|
289
|
+
* abortMultipartUploadsTransition: {
|
|
290
|
+
* condition: { type: "Age", maxAge: 60 * 60 * 24 * 7 },
|
|
291
|
+
* },
|
|
292
|
+
* },
|
|
293
|
+
* ],
|
|
294
|
+
* });
|
|
295
|
+
* ```
|
|
92
296
|
*/
|
|
93
297
|
export const R2Bucket = Resource<R2Bucket>("Cloudflare.R2Bucket")({
|
|
94
298
|
bind: R2BucketBinding.bind,
|
|
@@ -98,6 +302,48 @@ export declare namespace R2Bucket {
|
|
|
98
302
|
export type StorageClass = "Standard" | "InfrequentAccess";
|
|
99
303
|
export type Jurisdiction = "default" | "eu" | "fedramp";
|
|
100
304
|
export type Location = "apac" | "eeur" | "enam" | "weur" | "wnam" | "oc";
|
|
305
|
+
export type LifecycleRule = {
|
|
306
|
+
id: string;
|
|
307
|
+
enabled: boolean;
|
|
308
|
+
prefix: string;
|
|
309
|
+
abortMultipartUploadsTransition:
|
|
310
|
+
| { condition: { type: "Age"; maxAge: number } | undefined }
|
|
311
|
+
| undefined;
|
|
312
|
+
deleteObjectsTransition:
|
|
313
|
+
| { condition: R2BucketLifecycleCondition | undefined }
|
|
314
|
+
| undefined;
|
|
315
|
+
storageClassTransitions:
|
|
316
|
+
| {
|
|
317
|
+
condition: R2BucketLifecycleCondition;
|
|
318
|
+
storageClass: "InfrequentAccess";
|
|
319
|
+
}[]
|
|
320
|
+
| undefined;
|
|
321
|
+
};
|
|
322
|
+
export type CustomDomain = {
|
|
323
|
+
domain: string;
|
|
324
|
+
zoneId: string | undefined;
|
|
325
|
+
enabled: boolean;
|
|
326
|
+
ciphers: string[] | undefined;
|
|
327
|
+
minTLS: "1.0" | "1.1" | "1.2" | "1.3" | undefined;
|
|
328
|
+
status:
|
|
329
|
+
| {
|
|
330
|
+
ownership:
|
|
331
|
+
| "pending"
|
|
332
|
+
| "active"
|
|
333
|
+
| "deactivated"
|
|
334
|
+
| "blocked"
|
|
335
|
+
| "error"
|
|
336
|
+
| "unknown";
|
|
337
|
+
ssl:
|
|
338
|
+
| "initializing"
|
|
339
|
+
| "pending"
|
|
340
|
+
| "active"
|
|
341
|
+
| "deactivated"
|
|
342
|
+
| "error"
|
|
343
|
+
| "unknown";
|
|
344
|
+
}
|
|
345
|
+
| undefined;
|
|
346
|
+
};
|
|
101
347
|
}
|
|
102
348
|
|
|
103
349
|
export const R2BucketProvider = () =>
|
|
@@ -109,6 +355,12 @@ export const R2BucketProvider = () =>
|
|
|
109
355
|
const patchBucket = yield* r2.patchBucket;
|
|
110
356
|
const deleteBucket = yield* r2.deleteBucket;
|
|
111
357
|
const getBucket = yield* r2.getBucket;
|
|
358
|
+
const listBucketDomainCustoms = yield* r2.listBucketDomainCustoms;
|
|
359
|
+
const createBucketDomainCustom = yield* r2.createBucketDomainCustom;
|
|
360
|
+
const updateBucketDomainCustom = yield* r2.updateBucketDomainCustom;
|
|
361
|
+
const deleteBucketDomainCustom = yield* r2.deleteBucketDomainCustom;
|
|
362
|
+
const getBucketLifecycle = yield* r2.getBucketLifecycle;
|
|
363
|
+
const putBucketLifecycle = yield* r2.putBucketLifecycle;
|
|
112
364
|
|
|
113
365
|
const createBucketName = (id: string, name: string | undefined) =>
|
|
114
366
|
Effect.gen(function* () {
|
|
@@ -126,6 +378,187 @@ export const R2BucketProvider = () =>
|
|
|
126
378
|
return location.toLowerCase() as R2Bucket.Location;
|
|
127
379
|
};
|
|
128
380
|
|
|
381
|
+
const listCustomDomains = (
|
|
382
|
+
bucketName: string,
|
|
383
|
+
jurisdiction: R2Bucket.Jurisdiction,
|
|
384
|
+
) =>
|
|
385
|
+
listBucketDomainCustoms({
|
|
386
|
+
accountId,
|
|
387
|
+
bucketName,
|
|
388
|
+
jurisdiction,
|
|
389
|
+
}).pipe(
|
|
390
|
+
Effect.retry({
|
|
391
|
+
while: isNoSuchBucket,
|
|
392
|
+
schedule: r2BucketEndpointConsistencySchedule,
|
|
393
|
+
}),
|
|
394
|
+
Effect.map((response) =>
|
|
395
|
+
response.domains.map(toCustomDomainAttributes),
|
|
396
|
+
),
|
|
397
|
+
Effect.catchTag("NoSuchBucket", () => Effect.succeed(undefined)),
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
const reconcileCustomDomains = (
|
|
401
|
+
bucketName: string,
|
|
402
|
+
jurisdiction: R2Bucket.Jurisdiction,
|
|
403
|
+
desired: R2BucketCustomDomain[],
|
|
404
|
+
previous: R2Bucket.CustomDomain[],
|
|
405
|
+
) =>
|
|
406
|
+
Effect.gen(function* () {
|
|
407
|
+
const observed = yield* listCustomDomains(bucketName, jurisdiction);
|
|
408
|
+
if (!observed) {
|
|
409
|
+
return yield* Effect.fail(
|
|
410
|
+
new Error(
|
|
411
|
+
`Cannot reconcile custom domains for missing R2 bucket "${bucketName}"`,
|
|
412
|
+
),
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
const observedByDomain = new Map(
|
|
416
|
+
observed.map((domain) => [domain.domain, domain]),
|
|
417
|
+
);
|
|
418
|
+
const desiredDomains = new Set(desired.map((domain) => domain.name));
|
|
419
|
+
|
|
420
|
+
// Remove domains that are no longer desired. Domains that keep the
|
|
421
|
+
// same hostname but move zones are intentionally skipped here and
|
|
422
|
+
// handled in the per-domain flow below.
|
|
423
|
+
yield* Effect.forEach(
|
|
424
|
+
previous,
|
|
425
|
+
(previousDomain) =>
|
|
426
|
+
desiredDomains.has(previousDomain.domain)
|
|
427
|
+
? Effect.void
|
|
428
|
+
: deleteBucketDomainCustom({
|
|
429
|
+
accountId,
|
|
430
|
+
bucketName,
|
|
431
|
+
domain: previousDomain.domain,
|
|
432
|
+
jurisdiction,
|
|
433
|
+
}).pipe(
|
|
434
|
+
Effect.catchIf(
|
|
435
|
+
isMissingCustomDomainOrBucket,
|
|
436
|
+
() => Effect.void,
|
|
437
|
+
),
|
|
438
|
+
),
|
|
439
|
+
{ concurrency: "unbounded" },
|
|
440
|
+
);
|
|
441
|
+
|
|
442
|
+
const applied = yield* Effect.forEach(
|
|
443
|
+
desired,
|
|
444
|
+
(domain) =>
|
|
445
|
+
Effect.gen(function* () {
|
|
446
|
+
const zoneId = yield* Zone.resolveZoneId({
|
|
447
|
+
accountId,
|
|
448
|
+
zone: domain.zone,
|
|
449
|
+
hostname: domain.name,
|
|
450
|
+
});
|
|
451
|
+
const observedDomain = observedByDomain.get(domain.name);
|
|
452
|
+
|
|
453
|
+
if (
|
|
454
|
+
observedDomain &&
|
|
455
|
+
sameCustomDomainConfig(observedDomain, domain, zoneId)
|
|
456
|
+
) {
|
|
457
|
+
return observedDomain;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (observedDomain && observedDomain.zoneId !== zoneId) {
|
|
461
|
+
// Cloudflare does not mutate the zone for an existing custom
|
|
462
|
+
// domain. This is not a duplicate of the stale-domain prune
|
|
463
|
+
// above: the hostname is still desired, so that prune skips it
|
|
464
|
+
// and this branch deletes only to recreate it in the new zone.
|
|
465
|
+
yield* deleteBucketDomainCustom({
|
|
466
|
+
accountId,
|
|
467
|
+
bucketName,
|
|
468
|
+
domain: domain.name,
|
|
469
|
+
jurisdiction,
|
|
470
|
+
}).pipe(
|
|
471
|
+
Effect.catchIf(
|
|
472
|
+
isMissingCustomDomainOrBucket,
|
|
473
|
+
() => Effect.void,
|
|
474
|
+
),
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (!observedDomain || observedDomain.zoneId !== zoneId) {
|
|
479
|
+
const created = yield* createBucketDomainCustom({
|
|
480
|
+
accountId,
|
|
481
|
+
bucketName,
|
|
482
|
+
jurisdiction,
|
|
483
|
+
domain: domain.name,
|
|
484
|
+
enabled: domain.enabled ?? true,
|
|
485
|
+
zoneId,
|
|
486
|
+
ciphers: domain.ciphers,
|
|
487
|
+
minTLS: domain.minTLS,
|
|
488
|
+
}).pipe(
|
|
489
|
+
Effect.retry({
|
|
490
|
+
while: isNoSuchBucket,
|
|
491
|
+
schedule: r2BucketEndpointConsistencySchedule,
|
|
492
|
+
}),
|
|
493
|
+
);
|
|
494
|
+
return toCustomDomainAttributes({ ...created, zoneId });
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
const updated = yield* updateBucketDomainCustom({
|
|
498
|
+
accountId,
|
|
499
|
+
bucketName,
|
|
500
|
+
domain: domain.name,
|
|
501
|
+
jurisdiction,
|
|
502
|
+
enabled: domain.enabled ?? true,
|
|
503
|
+
ciphers: domain.ciphers,
|
|
504
|
+
minTLS: domain.minTLS,
|
|
505
|
+
}).pipe(
|
|
506
|
+
Effect.retry({
|
|
507
|
+
while: isNoSuchBucket,
|
|
508
|
+
schedule: r2BucketEndpointConsistencySchedule,
|
|
509
|
+
}),
|
|
510
|
+
);
|
|
511
|
+
return toCustomDomainAttributes({
|
|
512
|
+
...updated,
|
|
513
|
+
enabled: updated.enabled ?? domain.enabled ?? true,
|
|
514
|
+
zoneId,
|
|
515
|
+
});
|
|
516
|
+
}),
|
|
517
|
+
{ concurrency: "unbounded" },
|
|
518
|
+
);
|
|
519
|
+
|
|
520
|
+
return applied.sort((a, b) => a.domain.localeCompare(b.domain));
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
const reconcileLifecycleRules = (
|
|
524
|
+
bucketName: string,
|
|
525
|
+
jurisdiction: R2Bucket.Jurisdiction,
|
|
526
|
+
desired: R2BucketLifecycleRule[],
|
|
527
|
+
) =>
|
|
528
|
+
Effect.gen(function* () {
|
|
529
|
+
const observed = yield* getBucketLifecycle({
|
|
530
|
+
accountId,
|
|
531
|
+
bucketName,
|
|
532
|
+
jurisdiction,
|
|
533
|
+
}).pipe(
|
|
534
|
+
Effect.retry({
|
|
535
|
+
while: isNoSuchBucket,
|
|
536
|
+
schedule: r2BucketEndpointConsistencySchedule,
|
|
537
|
+
}),
|
|
538
|
+
);
|
|
539
|
+
|
|
540
|
+
const observedRules = (observed.rules ?? []).map(toLifecycleRule);
|
|
541
|
+
const desiredRules = desired.map(normalizeLifecycleRule);
|
|
542
|
+
|
|
543
|
+
if (deepEqual(observedRules, desiredRules)) {
|
|
544
|
+
return desiredRules;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
yield* putBucketLifecycle({
|
|
548
|
+
accountId,
|
|
549
|
+
bucketName,
|
|
550
|
+
jurisdiction,
|
|
551
|
+
rules: desired.map(toLifecyclePutPayload),
|
|
552
|
+
}).pipe(
|
|
553
|
+
Effect.retry({
|
|
554
|
+
while: isNoSuchBucket,
|
|
555
|
+
schedule: r2BucketEndpointConsistencySchedule,
|
|
556
|
+
}),
|
|
557
|
+
);
|
|
558
|
+
|
|
559
|
+
return desiredRules;
|
|
560
|
+
});
|
|
561
|
+
|
|
129
562
|
return {
|
|
130
563
|
stables: ["bucketName", "accountId"],
|
|
131
564
|
diff: Effect.fn(function* ({ id, olds = {}, news = {}, output }) {
|
|
@@ -152,6 +585,12 @@ export const R2BucketProvider = () =>
|
|
|
152
585
|
stables: oldName === name ? ["bucketName"] : undefined,
|
|
153
586
|
} as const;
|
|
154
587
|
}
|
|
588
|
+
if (!deepEqual(olds.domains, news.domains)) {
|
|
589
|
+
return { action: "update" } as const;
|
|
590
|
+
}
|
|
591
|
+
if (!deepEqual(olds.lifecycleRules, news.lifecycleRules)) {
|
|
592
|
+
return { action: "update" } as const;
|
|
593
|
+
}
|
|
155
594
|
}),
|
|
156
595
|
reconcile: Effect.fn(function* ({ id, news = {}, output }) {
|
|
157
596
|
const name = yield* createBucketName(id, news.name);
|
|
@@ -206,15 +645,44 @@ export const R2BucketProvider = () =>
|
|
|
206
645
|
});
|
|
207
646
|
}
|
|
208
647
|
|
|
209
|
-
|
|
648
|
+
const attrs = {
|
|
210
649
|
bucketName: observed.name!,
|
|
211
650
|
storageClass: observed.storageClass ?? "Standard",
|
|
212
651
|
jurisdiction: observed.jurisdiction ?? "default",
|
|
213
652
|
location: normalizeLocation(observed.location),
|
|
214
653
|
accountId: acct,
|
|
215
654
|
};
|
|
655
|
+
|
|
656
|
+
const domains = yield* reconcileCustomDomains(
|
|
657
|
+
attrs.bucketName,
|
|
658
|
+
attrs.jurisdiction,
|
|
659
|
+
news.domains ?? [],
|
|
660
|
+
output?.domains ?? [],
|
|
661
|
+
);
|
|
662
|
+
|
|
663
|
+
const lifecycleRules = yield* reconcileLifecycleRules(
|
|
664
|
+
attrs.bucketName,
|
|
665
|
+
attrs.jurisdiction,
|
|
666
|
+
news.lifecycleRules ?? [],
|
|
667
|
+
);
|
|
668
|
+
|
|
669
|
+
return {
|
|
670
|
+
...attrs,
|
|
671
|
+
domains,
|
|
672
|
+
lifecycleRules,
|
|
673
|
+
};
|
|
216
674
|
}),
|
|
217
675
|
delete: Effect.fn(function* ({ output }) {
|
|
676
|
+
for (const domain of output.domains ?? []) {
|
|
677
|
+
yield* deleteBucketDomainCustom({
|
|
678
|
+
accountId: output.accountId,
|
|
679
|
+
bucketName: output.bucketName,
|
|
680
|
+
domain: domain.domain,
|
|
681
|
+
jurisdiction: output.jurisdiction,
|
|
682
|
+
}).pipe(
|
|
683
|
+
Effect.catchIf(isMissingCustomDomainOrBucket, () => Effect.void),
|
|
684
|
+
);
|
|
685
|
+
}
|
|
218
686
|
yield* deleteBucket({
|
|
219
687
|
accountId: output.accountId,
|
|
220
688
|
bucketName: output.bucketName,
|
|
@@ -236,6 +704,8 @@ export const R2BucketProvider = () =>
|
|
|
236
704
|
jurisdiction: bucket.jurisdiction ?? "default",
|
|
237
705
|
location: normalizeLocation(bucket.location),
|
|
238
706
|
accountId: acct,
|
|
707
|
+
domains: output?.domains ?? [],
|
|
708
|
+
lifecycleRules: output?.lifecycleRules ?? [],
|
|
239
709
|
})),
|
|
240
710
|
Effect.catchTag("NoSuchBucket", () => Effect.succeed(undefined)),
|
|
241
711
|
);
|
|
@@ -243,3 +713,101 @@ export const R2BucketProvider = () =>
|
|
|
243
713
|
};
|
|
244
714
|
}),
|
|
245
715
|
);
|
|
716
|
+
|
|
717
|
+
// R2 can make a newly-created bucket visible to `getBucket` before its
|
|
718
|
+
// sub-resource endpoints (custom domains, lifecycle) accept it. Retry only
|
|
719
|
+
// that narrow `NoSuchBucket` lag here; not-found sub-resources are still
|
|
720
|
+
// treated as terminal for idempotent deletes.
|
|
721
|
+
const r2BucketEndpointConsistencySchedule = Schedule.exponential(100).pipe(
|
|
722
|
+
Schedule.both(Schedule.recurs(5)),
|
|
723
|
+
);
|
|
724
|
+
|
|
725
|
+
type CustomDomainResponse = {
|
|
726
|
+
domain: string;
|
|
727
|
+
zoneId?: string | null;
|
|
728
|
+
enabled?: boolean | null;
|
|
729
|
+
ciphers?: string[] | null;
|
|
730
|
+
minTLS?: "1.0" | "1.1" | "1.2" | "1.3" | null;
|
|
731
|
+
status?: R2Bucket.CustomDomain["status"];
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
const toCustomDomainAttributes = (
|
|
735
|
+
domain: CustomDomainResponse,
|
|
736
|
+
): R2Bucket.CustomDomain => ({
|
|
737
|
+
domain: domain.domain,
|
|
738
|
+
zoneId: domain.zoneId ?? undefined,
|
|
739
|
+
enabled: domain.enabled ?? true,
|
|
740
|
+
ciphers: domain.ciphers ?? undefined,
|
|
741
|
+
minTLS: domain.minTLS ?? undefined,
|
|
742
|
+
status: domain.status,
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
const sameCustomDomainConfig = (
|
|
746
|
+
observed: R2Bucket.CustomDomain | undefined,
|
|
747
|
+
desired: R2BucketCustomDomain,
|
|
748
|
+
zoneId: string,
|
|
749
|
+
): boolean =>
|
|
750
|
+
observed !== undefined &&
|
|
751
|
+
observed.zoneId === zoneId &&
|
|
752
|
+
observed.enabled === (desired.enabled ?? true) &&
|
|
753
|
+
deepEqual(observed.ciphers, desired.ciphers) &&
|
|
754
|
+
observed.minTLS === desired.minTLS;
|
|
755
|
+
|
|
756
|
+
const isMissingCustomDomainOrBucket = (error: unknown): boolean =>
|
|
757
|
+
typeof error === "object" &&
|
|
758
|
+
error !== null &&
|
|
759
|
+
(("status" in error && (error as { status: unknown }).status === 404) ||
|
|
760
|
+
("_tag" in error &&
|
|
761
|
+
((error as { _tag: unknown })._tag === "DomainNotFound" ||
|
|
762
|
+
(error as { _tag: unknown })._tag === "NoSuchBucket")));
|
|
763
|
+
|
|
764
|
+
type LifecycleRuleResponse = NonNullable<
|
|
765
|
+
r2.GetBucketLifecycleResponse["rules"]
|
|
766
|
+
>[number];
|
|
767
|
+
|
|
768
|
+
const toLifecycleRule = (
|
|
769
|
+
rule: LifecycleRuleResponse,
|
|
770
|
+
): R2Bucket.LifecycleRule => ({
|
|
771
|
+
id: rule.id,
|
|
772
|
+
enabled: rule.enabled,
|
|
773
|
+
prefix: rule.conditions.prefix ?? "",
|
|
774
|
+
abortMultipartUploadsTransition: rule.abortMultipartUploadsTransition
|
|
775
|
+
? { condition: rule.abortMultipartUploadsTransition.condition ?? undefined }
|
|
776
|
+
: undefined,
|
|
777
|
+
deleteObjectsTransition: rule.deleteObjectsTransition
|
|
778
|
+
? { condition: rule.deleteObjectsTransition.condition ?? undefined }
|
|
779
|
+
: undefined,
|
|
780
|
+
storageClassTransitions: rule.storageClassTransitions ?? undefined,
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
const normalizeLifecycleRule = (
|
|
784
|
+
rule: R2BucketLifecycleRule,
|
|
785
|
+
): R2Bucket.LifecycleRule => ({
|
|
786
|
+
id: rule.id,
|
|
787
|
+
enabled: rule.enabled ?? true,
|
|
788
|
+
prefix: rule.prefix ?? "",
|
|
789
|
+
abortMultipartUploadsTransition: rule.abortMultipartUploadsTransition
|
|
790
|
+
? { condition: rule.abortMultipartUploadsTransition.condition }
|
|
791
|
+
: undefined,
|
|
792
|
+
deleteObjectsTransition: rule.deleteObjectsTransition
|
|
793
|
+
? { condition: rule.deleteObjectsTransition.condition }
|
|
794
|
+
: undefined,
|
|
795
|
+
storageClassTransitions: rule.storageClassTransitions,
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
const toLifecyclePutPayload = (
|
|
799
|
+
rule: R2BucketLifecycleRule,
|
|
800
|
+
): NonNullable<r2.PutBucketLifecycleRequest["rules"]>[number] => ({
|
|
801
|
+
id: rule.id,
|
|
802
|
+
enabled: rule.enabled ?? true,
|
|
803
|
+
conditions: { prefix: rule.prefix ?? "" },
|
|
804
|
+
abortMultipartUploadsTransition: rule.abortMultipartUploadsTransition,
|
|
805
|
+
deleteObjectsTransition: rule.deleteObjectsTransition,
|
|
806
|
+
storageClassTransitions: rule.storageClassTransitions,
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
const isNoSuchBucket = (error: unknown): boolean =>
|
|
810
|
+
typeof error === "object" &&
|
|
811
|
+
error !== null &&
|
|
812
|
+
"_tag" in error &&
|
|
813
|
+
(error as { _tag: unknown })._tag === "NoSuchBucket";
|