alchemy 2.0.0-beta.61 → 2.0.0-beta.63
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/README.md +26 -11
- package/bin/exec.js +2023 -75
- package/bin/exec.js.map +1 -1
- package/lib/AWS/ACM/Certificate.d.ts.map +1 -1
- package/lib/AWS/ACM/Certificate.js +16 -4
- package/lib/AWS/ACM/Certificate.js.map +1 -1
- package/lib/AWS/ApiGateway/common.d.ts.map +1 -1
- package/lib/AWS/ApiGateway/common.js +6 -3
- package/lib/AWS/ApiGateway/common.js.map +1 -1
- package/lib/AWS/AuthProvider.d.ts.map +1 -1
- package/lib/AWS/AuthProvider.js +2 -2
- package/lib/AWS/AuthProvider.js.map +1 -1
- package/lib/AWS/AutoScaling/AutoScalingGroup.d.ts.map +1 -1
- package/lib/AWS/AutoScaling/AutoScalingGroup.js +8 -2
- package/lib/AWS/AutoScaling/AutoScalingGroup.js.map +1 -1
- package/lib/AWS/Bootstrap.d.ts.map +1 -1
- package/lib/AWS/Bootstrap.js +5 -2
- package/lib/AWS/Bootstrap.js.map +1 -1
- package/lib/AWS/CloudFront/Distribution.d.ts.map +1 -1
- package/lib/AWS/CloudFront/Distribution.js +20 -5
- package/lib/AWS/CloudFront/Distribution.js.map +1 -1
- package/lib/AWS/CloudFront/Function.js +5 -2
- package/lib/AWS/CloudFront/Function.js.map +1 -1
- package/lib/AWS/CloudFront/Invalidation.d.ts.map +1 -1
- package/lib/AWS/CloudFront/Invalidation.js +4 -1
- package/lib/AWS/CloudFront/Invalidation.js.map +1 -1
- package/lib/AWS/CloudFront/KvEntries.d.ts.map +1 -1
- package/lib/AWS/CloudFront/KvEntries.js +4 -1
- package/lib/AWS/CloudFront/KvEntries.js.map +1 -1
- package/lib/AWS/CloudFront/KvRoutesUpdate.d.ts.map +1 -1
- package/lib/AWS/CloudFront/KvRoutesUpdate.js +8 -2
- package/lib/AWS/CloudFront/KvRoutesUpdate.js.map +1 -1
- package/lib/AWS/CloudFront/VpcOrigin.d.ts.map +1 -1
- package/lib/AWS/CloudFront/VpcOrigin.js +12 -3
- package/lib/AWS/CloudFront/VpcOrigin.js.map +1 -1
- package/lib/AWS/CloudFront/common.d.ts.map +1 -1
- package/lib/AWS/CloudFront/common.js +5 -2
- package/lib/AWS/CloudFront/common.js.map +1 -1
- package/lib/AWS/CloudWatch/AnomalyDetector.d.ts.map +1 -1
- package/lib/AWS/CloudWatch/AnomalyDetector.js +4 -1
- package/lib/AWS/CloudWatch/AnomalyDetector.js.map +1 -1
- package/lib/AWS/CloudWatch/common.d.ts.map +1 -1
- package/lib/AWS/CloudWatch/common.js +1 -1
- package/lib/AWS/CloudWatch/common.js.map +1 -1
- package/lib/AWS/DynamoDB/Table.d.ts.map +1 -1
- package/lib/AWS/DynamoDB/Table.js +53 -20
- package/lib/AWS/DynamoDB/Table.js.map +1 -1
- package/lib/AWS/EC2/EIP.d.ts.map +1 -1
- package/lib/AWS/EC2/EIP.js +4 -1
- package/lib/AWS/EC2/EIP.js.map +1 -1
- package/lib/AWS/EC2/EgressOnlyInternetGateway.d.ts.map +1 -1
- package/lib/AWS/EC2/EgressOnlyInternetGateway.js +4 -2
- package/lib/AWS/EC2/EgressOnlyInternetGateway.js.map +1 -1
- package/lib/AWS/EC2/Instance.d.ts.map +1 -1
- package/lib/AWS/EC2/Instance.js +12 -3
- package/lib/AWS/EC2/Instance.js.map +1 -1
- package/lib/AWS/EC2/InternetGateway.d.ts.map +1 -1
- package/lib/AWS/EC2/InternetGateway.js +12 -5
- package/lib/AWS/EC2/InternetGateway.js.map +1 -1
- package/lib/AWS/EC2/NatGateway.js +2 -4
- package/lib/AWS/EC2/NatGateway.js.map +1 -1
- package/lib/AWS/EC2/NetworkAcl.d.ts.map +1 -1
- package/lib/AWS/EC2/NetworkAcl.js +4 -1
- package/lib/AWS/EC2/NetworkAcl.js.map +1 -1
- package/lib/AWS/EC2/NetworkAclEntry.d.ts.map +1 -1
- package/lib/AWS/EC2/NetworkAclEntry.js +4 -1
- package/lib/AWS/EC2/NetworkAclEntry.js.map +1 -1
- package/lib/AWS/EC2/RouteTable.d.ts.map +1 -1
- package/lib/AWS/EC2/RouteTable.js +8 -6
- package/lib/AWS/EC2/RouteTable.js.map +1 -1
- package/lib/AWS/EC2/RouteTableAssociation.js +2 -5
- package/lib/AWS/EC2/RouteTableAssociation.js.map +1 -1
- package/lib/AWS/EC2/SecurityGroup.d.ts.map +1 -1
- package/lib/AWS/EC2/SecurityGroup.js +8 -3
- package/lib/AWS/EC2/SecurityGroup.js.map +1 -1
- package/lib/AWS/EC2/Subnet.d.ts.map +1 -1
- package/lib/AWS/EC2/Subnet.js +10 -6
- package/lib/AWS/EC2/Subnet.js.map +1 -1
- package/lib/AWS/EC2/Vpc.d.ts.map +1 -1
- package/lib/AWS/EC2/Vpc.js +7 -7
- package/lib/AWS/EC2/Vpc.js.map +1 -1
- package/lib/AWS/EC2/VpcEndpoint.js +2 -4
- package/lib/AWS/EC2/VpcEndpoint.js.map +1 -1
- package/lib/AWS/EC2/hosted.d.ts.map +1 -1
- package/lib/AWS/EC2/hosted.js +2 -1
- package/lib/AWS/EC2/hosted.js.map +1 -1
- package/lib/AWS/ECS/Service.d.ts.map +1 -1
- package/lib/AWS/ECS/Service.js +4 -1
- package/lib/AWS/ECS/Service.js.map +1 -1
- package/lib/AWS/ECS/Task.d.ts.map +1 -1
- package/lib/AWS/ECS/Task.js +2 -1
- package/lib/AWS/ECS/Task.js.map +1 -1
- package/lib/AWS/EKS/Addon.js +8 -2
- package/lib/AWS/EKS/Addon.js.map +1 -1
- package/lib/AWS/EKS/Cluster.d.ts.map +1 -1
- package/lib/AWS/EKS/Cluster.js +4 -1
- package/lib/AWS/EKS/Cluster.js.map +1 -1
- package/lib/AWS/ELBv2/TargetGroup.d.ts.map +1 -1
- package/lib/AWS/ELBv2/TargetGroup.js +4 -1
- package/lib/AWS/ELBv2/TargetGroup.js.map +1 -1
- package/lib/AWS/ELBv2/TrustStore.d.ts.map +1 -1
- package/lib/AWS/ELBv2/TrustStore.js +4 -1
- package/lib/AWS/ELBv2/TrustStore.js.map +1 -1
- package/lib/AWS/IAM/SAMLProvider.js +4 -1
- package/lib/AWS/IAM/SAMLProvider.js.map +1 -1
- package/lib/AWS/IdentityCenter/AccountAssignment.js +8 -2
- package/lib/AWS/IdentityCenter/AccountAssignment.js.map +1 -1
- package/lib/AWS/IdentityCenter/common.d.ts.map +1 -1
- package/lib/AWS/IdentityCenter/common.js +1 -1
- package/lib/AWS/IdentityCenter/common.js.map +1 -1
- package/lib/AWS/KMS/Alias.js +4 -1
- package/lib/AWS/KMS/Alias.js.map +1 -1
- package/lib/AWS/KMS/Key.js +4 -1
- package/lib/AWS/KMS/Key.js.map +1 -1
- package/lib/AWS/Kinesis/Stream.d.ts.map +1 -1
- package/lib/AWS/Kinesis/Stream.js +2 -2
- package/lib/AWS/Kinesis/Stream.js.map +1 -1
- package/lib/AWS/Kinesis/StreamConsumer.d.ts.map +1 -1
- package/lib/AWS/Kinesis/StreamConsumer.js +7 -4
- package/lib/AWS/Kinesis/StreamConsumer.js.map +1 -1
- package/lib/AWS/Lambda/Alias.d.ts.map +1 -1
- package/lib/AWS/Lambda/Alias.js +4 -1
- package/lib/AWS/Lambda/Alias.js.map +1 -1
- package/lib/AWS/Lambda/EventInvokeConfig.d.ts.map +1 -1
- package/lib/AWS/Lambda/EventInvokeConfig.js +2 -2
- package/lib/AWS/Lambda/EventInvokeConfig.js.map +1 -1
- package/lib/AWS/Lambda/EventSourceMapping.d.ts.map +1 -1
- package/lib/AWS/Lambda/EventSourceMapping.js +10 -4
- package/lib/AWS/Lambda/EventSourceMapping.js.map +1 -1
- package/lib/AWS/Lambda/Function.d.ts +16 -1
- package/lib/AWS/Lambda/Function.d.ts.map +1 -1
- package/lib/AWS/Lambda/Function.js +113 -65
- package/lib/AWS/Lambda/Function.js.map +1 -1
- package/lib/AWS/Lambda/MicrovmProvider.d.ts.map +1 -1
- package/lib/AWS/Lambda/MicrovmProvider.js +13 -5
- package/lib/AWS/Lambda/MicrovmProvider.js.map +1 -1
- package/lib/AWS/Lambda/MicrovmRuntimeContext.d.ts.map +1 -1
- package/lib/AWS/Lambda/MicrovmRuntimeContext.js +9 -21
- package/lib/AWS/Lambda/MicrovmRuntimeContext.js.map +1 -1
- package/lib/AWS/Lambda/NetworkConnector.js +13 -5
- package/lib/AWS/Lambda/NetworkConnector.js.map +1 -1
- package/lib/AWS/Lambda/RuntimeExtension.d.ts +27 -0
- package/lib/AWS/Lambda/RuntimeExtension.d.ts.map +1 -0
- package/lib/AWS/Lambda/RuntimeExtension.js +49 -0
- package/lib/AWS/Lambda/RuntimeExtension.js.map +1 -0
- package/lib/AWS/Organizations/Account.js +5 -2
- package/lib/AWS/Organizations/Account.js.map +1 -1
- package/lib/AWS/Organizations/common.d.ts.map +1 -1
- package/lib/AWS/Organizations/common.js +1 -1
- package/lib/AWS/Organizations/common.js.map +1 -1
- package/lib/AWS/Providers.js +14 -12
- package/lib/AWS/Providers.js.map +1 -1
- package/lib/AWS/RDS/DBCluster.d.ts.map +1 -1
- package/lib/AWS/RDS/DBCluster.js +8 -2
- package/lib/AWS/RDS/DBCluster.js.map +1 -1
- package/lib/AWS/RDS/DBInstance.d.ts.map +1 -1
- package/lib/AWS/RDS/DBInstance.js +8 -2
- package/lib/AWS/RDS/DBInstance.js.map +1 -1
- package/lib/AWS/RDS/DBProxy.d.ts.map +1 -1
- package/lib/AWS/RDS/DBProxy.js +4 -1
- package/lib/AWS/RDS/DBProxy.js.map +1 -1
- package/lib/AWS/RDS/DBProxyEndpoint.d.ts.map +1 -1
- package/lib/AWS/RDS/DBProxyEndpoint.js +4 -1
- package/lib/AWS/RDS/DBProxyEndpoint.js.map +1 -1
- package/lib/AWS/Route53/HealthCheck.d.ts.map +1 -1
- package/lib/AWS/Route53/HealthCheck.js +8 -2
- package/lib/AWS/Route53/HealthCheck.js.map +1 -1
- package/lib/AWS/Route53/HostedZone.d.ts.map +1 -1
- package/lib/AWS/Route53/HostedZone.js +8 -2
- package/lib/AWS/Route53/HostedZone.js.map +1 -1
- package/lib/AWS/Route53/Record.d.ts.map +1 -1
- package/lib/AWS/Route53/Record.js +4 -1
- package/lib/AWS/Route53/Record.js.map +1 -1
- package/lib/AWS/S3/Bucket.d.ts.map +1 -1
- package/lib/AWS/S3/Bucket.js +5 -2
- package/lib/AWS/S3/Bucket.js.map +1 -1
- package/lib/AWS/SQS/Queue.d.ts.map +1 -1
- package/lib/AWS/SQS/Queue.js +25 -7
- package/lib/AWS/SQS/Queue.js.map +1 -1
- package/lib/AWS/StateStore/State.js +5 -2
- package/lib/AWS/StateStore/State.js.map +1 -1
- package/lib/AWS/Website/AssetDeployment.js +5 -2
- package/lib/AWS/Website/AssetDeployment.js.map +1 -1
- package/lib/Action.d.ts +8 -0
- package/lib/Action.d.ts.map +1 -1
- package/lib/Action.js +16 -5
- package/lib/Action.js.map +1 -1
- package/lib/ActionRuntimeContext.d.ts +14 -0
- package/lib/ActionRuntimeContext.d.ts.map +1 -0
- package/lib/ActionRuntimeContext.js +56 -0
- package/lib/ActionRuntimeContext.js.map +1 -0
- package/lib/Apply.d.ts.map +1 -1
- package/lib/Apply.js +48 -6
- package/lib/Apply.js.map +1 -1
- package/lib/Auth/AuthProvider.d.ts +10 -0
- package/lib/Auth/AuthProvider.d.ts.map +1 -1
- package/lib/Auth/AuthProvider.js +10 -0
- package/lib/Auth/AuthProvider.js.map +1 -1
- package/lib/Auth/Lock.d.ts.map +1 -1
- package/lib/Auth/Lock.js +5 -2
- package/lib/Auth/Lock.js.map +1 -1
- package/lib/Axiom/AuthProvider.d.ts.map +1 -1
- package/lib/Axiom/AuthProvider.js +1 -1
- package/lib/Axiom/AuthProvider.js.map +1 -1
- package/lib/Bundle/PurePlugin.d.ts.map +1 -1
- package/lib/Bundle/PurePlugin.js +26 -1
- package/lib/Bundle/PurePlugin.js.map +1 -1
- package/lib/Bundle/Vite.d.ts +3 -1
- package/lib/Bundle/Vite.d.ts.map +1 -1
- package/lib/Bundle/Vite.js +38 -13
- package/lib/Bundle/Vite.js.map +1 -1
- package/lib/Cli/LoggingCli.d.ts.map +1 -1
- package/lib/Cli/LoggingCli.js +7 -4
- package/lib/Cli/LoggingCli.js.map +1 -1
- package/lib/Cli/commands/_shared.d.ts +74 -5
- package/lib/Cli/commands/_shared.d.ts.map +1 -1
- package/lib/Cli/commands/_shared.js +84 -2
- package/lib/Cli/commands/_shared.js.map +1 -1
- package/lib/Cli/commands/login.d.ts +7 -3
- package/lib/Cli/commands/login.d.ts.map +1 -1
- package/lib/Cli/commands/login.js +71 -24
- package/lib/Cli/commands/login.js.map +1 -1
- package/lib/Cli/commands/logs.d.ts.map +1 -1
- package/lib/Cli/commands/logs.js +1 -0
- package/lib/Cli/commands/logs.js.map +1 -1
- package/lib/Cli/commands/nuke.d.ts.map +1 -1
- package/lib/Cli/commands/nuke.js +15 -24
- package/lib/Cli/commands/nuke.js.map +1 -1
- package/lib/Cli/commands/profile.d.ts +23 -1
- package/lib/Cli/commands/profile.d.ts.map +1 -1
- package/lib/Cli/commands/profile.js +46 -22
- package/lib/Cli/commands/profile.js.map +1 -1
- package/lib/Cli/commands/tail.d.ts.map +1 -1
- package/lib/Cli/commands/tail.js +1 -0
- package/lib/Cli/commands/tail.js.map +1 -1
- package/lib/Cloudflare/AI/GatewayDynamicRouting.d.ts.map +1 -1
- package/lib/Cloudflare/AI/GatewayDynamicRouting.js +31 -2
- package/lib/Cloudflare/AI/GatewayDynamicRouting.js.map +1 -1
- package/lib/Cloudflare/AI/LanguageModel.js +21 -4
- package/lib/Cloudflare/AI/LanguageModel.js.map +1 -1
- package/lib/Cloudflare/AI/QuerySearchLocal.d.ts +37 -0
- package/lib/Cloudflare/AI/QuerySearchLocal.d.ts.map +1 -0
- package/lib/Cloudflare/AI/QuerySearchLocal.js +53 -0
- package/lib/Cloudflare/AI/QuerySearchLocal.js.map +1 -0
- package/lib/Cloudflare/AI/QuerySearchNamespaceLocal.d.ts +35 -0
- package/lib/Cloudflare/AI/QuerySearchNamespaceLocal.d.ts.map +1 -0
- package/lib/Cloudflare/AI/QuerySearchNamespaceLocal.js +47 -0
- package/lib/Cloudflare/AI/QuerySearchNamespaceLocal.js.map +1 -0
- package/lib/Cloudflare/AI/SearchHttpClient.d.ts +34 -0
- package/lib/Cloudflare/AI/SearchHttpClient.d.ts.map +1 -0
- package/lib/Cloudflare/AI/SearchHttpClient.js +262 -0
- package/lib/Cloudflare/AI/SearchHttpClient.js.map +1 -0
- package/lib/Cloudflare/AI/SearchInstance.js +4 -1
- package/lib/Cloudflare/AI/SearchInstance.js.map +1 -1
- package/lib/Cloudflare/AI/index.d.ts +2 -0
- package/lib/Cloudflare/AI/index.d.ts.map +1 -1
- package/lib/Cloudflare/AI/index.js +2 -0
- package/lib/Cloudflare/AI/index.js.map +1 -1
- package/lib/Cloudflare/Access/Application.d.ts.map +1 -1
- package/lib/Cloudflare/Access/Application.js +7 -1
- package/lib/Cloudflare/Access/Application.js.map +1 -1
- package/lib/Cloudflare/Alerting/Silence.d.ts.map +1 -1
- package/lib/Cloudflare/Alerting/Silence.js +4 -1
- package/lib/Cloudflare/Alerting/Silence.js.map +1 -1
- package/lib/Cloudflare/Alerting/Webhook.d.ts.map +1 -1
- package/lib/Cloudflare/Alerting/Webhook.js +8 -2
- package/lib/Cloudflare/Alerting/Webhook.js.map +1 -1
- package/lib/Cloudflare/Auth/AuthProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Auth/AuthProvider.js +23 -8
- package/lib/Cloudflare/Auth/AuthProvider.js.map +1 -1
- package/lib/Cloudflare/Auth/OAuthClient.d.ts.map +1 -1
- package/lib/Cloudflare/Auth/OAuthClient.js +6 -7
- package/lib/Cloudflare/Auth/OAuthClient.js.map +1 -1
- package/lib/Cloudflare/Cache/RegionalTieredCache.d.ts.map +1 -1
- package/lib/Cloudflare/Cache/RegionalTieredCache.js +7 -1
- package/lib/Cloudflare/Cache/RegionalTieredCache.js.map +1 -1
- package/lib/Cloudflare/Containers/ContainerApplication.d.ts +18 -2
- package/lib/Cloudflare/Containers/ContainerApplication.d.ts.map +1 -1
- package/lib/Cloudflare/Containers/ContainerApplication.js +1 -0
- package/lib/Cloudflare/Containers/ContainerApplication.js.map +1 -1
- package/lib/Cloudflare/Containers/ContainerBundle.d.ts +29 -3
- package/lib/Cloudflare/Containers/ContainerBundle.d.ts.map +1 -1
- package/lib/Cloudflare/Containers/ContainerBundle.js +84 -23
- package/lib/Cloudflare/Containers/ContainerBundle.js.map +1 -1
- package/lib/Cloudflare/Containers/ContainerPlatform.d.ts.map +1 -1
- package/lib/Cloudflare/Containers/ContainerPlatform.js +12 -33
- package/lib/Cloudflare/Containers/ContainerPlatform.js.map +1 -1
- package/lib/Cloudflare/Containers/ContainerProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Containers/ContainerProvider.js +53 -14
- package/lib/Cloudflare/Containers/ContainerProvider.js.map +1 -1
- package/lib/Cloudflare/Containers/LocalContainerProvider.d.ts +6 -6
- package/lib/Cloudflare/Containers/LocalContainerProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Containers/LocalContainerProvider.js +69 -47
- package/lib/Cloudflare/Containers/LocalContainerProvider.js.map +1 -1
- package/lib/Cloudflare/D1/QueryDatabaseHttpClient.d.ts +24 -0
- package/lib/Cloudflare/D1/QueryDatabaseHttpClient.d.ts.map +1 -0
- package/lib/Cloudflare/D1/QueryDatabaseHttpClient.js +106 -0
- package/lib/Cloudflare/D1/QueryDatabaseHttpClient.js.map +1 -0
- package/lib/Cloudflare/D1/QueryDatabaseLocal.d.ts +38 -0
- package/lib/Cloudflare/D1/QueryDatabaseLocal.d.ts.map +1 -0
- package/lib/Cloudflare/D1/QueryDatabaseLocal.js +54 -0
- package/lib/Cloudflare/D1/QueryDatabaseLocal.js.map +1 -0
- package/lib/Cloudflare/D1/index.d.ts +1 -0
- package/lib/Cloudflare/D1/index.d.ts.map +1 -1
- package/lib/Cloudflare/D1/index.js +1 -0
- package/lib/Cloudflare/D1/index.js.map +1 -1
- package/lib/Cloudflare/DNS/DnsHttp.d.ts +16 -1
- package/lib/Cloudflare/DNS/DnsHttp.d.ts.map +1 -1
- package/lib/Cloudflare/DNS/DnsHttp.js +6 -1
- package/lib/Cloudflare/DNS/DnsHttp.js.map +1 -1
- package/lib/Cloudflare/DNS/DnsLocal.d.ts +22 -0
- package/lib/Cloudflare/DNS/DnsLocal.d.ts.map +1 -0
- package/lib/Cloudflare/DNS/DnsLocal.js +31 -0
- package/lib/Cloudflare/DNS/DnsLocal.js.map +1 -0
- package/lib/Cloudflare/DNS/ReadDnsHttp.d.ts +3 -3
- package/lib/Cloudflare/DNS/ReadDnsHttp.d.ts.map +1 -1
- package/lib/Cloudflare/DNS/ReadDnsHttp.js +3 -4
- package/lib/Cloudflare/DNS/ReadDnsHttp.js.map +1 -1
- package/lib/Cloudflare/DNS/ReadDnsLocal.d.ts +32 -0
- package/lib/Cloudflare/DNS/ReadDnsLocal.d.ts.map +1 -0
- package/lib/Cloudflare/DNS/ReadDnsLocal.js +35 -0
- package/lib/Cloudflare/DNS/ReadDnsLocal.js.map +1 -0
- package/lib/Cloudflare/DNS/ReadWriteDnsHttp.d.ts +3 -3
- package/lib/Cloudflare/DNS/ReadWriteDnsHttp.d.ts.map +1 -1
- package/lib/Cloudflare/DNS/ReadWriteDnsHttp.js +4 -4
- package/lib/Cloudflare/DNS/ReadWriteDnsHttp.js.map +1 -1
- package/lib/Cloudflare/DNS/ReadWriteDnsLocal.d.ts +40 -0
- package/lib/Cloudflare/DNS/ReadWriteDnsLocal.d.ts.map +1 -0
- package/lib/Cloudflare/DNS/ReadWriteDnsLocal.js +43 -0
- package/lib/Cloudflare/DNS/ReadWriteDnsLocal.js.map +1 -0
- package/lib/Cloudflare/DNS/WriteDnsHttp.d.ts +3 -3
- package/lib/Cloudflare/DNS/WriteDnsHttp.d.ts.map +1 -1
- package/lib/Cloudflare/DNS/WriteDnsHttp.js +3 -4
- package/lib/Cloudflare/DNS/WriteDnsHttp.js.map +1 -1
- package/lib/Cloudflare/DNS/WriteDnsLocal.d.ts +38 -0
- package/lib/Cloudflare/DNS/WriteDnsLocal.d.ts.map +1 -0
- package/lib/Cloudflare/DNS/WriteDnsLocal.js +41 -0
- package/lib/Cloudflare/DNS/WriteDnsLocal.js.map +1 -0
- package/lib/Cloudflare/DNS/index.d.ts +3 -0
- package/lib/Cloudflare/DNS/index.d.ts.map +1 -1
- package/lib/Cloudflare/DNS/index.js +3 -0
- package/lib/Cloudflare/DNS/index.js.map +1 -1
- package/lib/Cloudflare/Diagnostics/EndpointHealthcheck.js +4 -1
- package/lib/Cloudflare/Diagnostics/EndpointHealthcheck.js.map +1 -1
- package/lib/Cloudflare/Flagship/ReadFlagsHttpClient.d.ts +27 -0
- package/lib/Cloudflare/Flagship/ReadFlagsHttpClient.d.ts.map +1 -0
- package/lib/Cloudflare/Flagship/ReadFlagsHttpClient.js +86 -0
- package/lib/Cloudflare/Flagship/ReadFlagsHttpClient.js.map +1 -0
- package/lib/Cloudflare/Flagship/ReadFlagsLocal.d.ts +41 -0
- package/lib/Cloudflare/Flagship/ReadFlagsLocal.d.ts.map +1 -0
- package/lib/Cloudflare/Flagship/ReadFlagsLocal.js +57 -0
- package/lib/Cloudflare/Flagship/ReadFlagsLocal.js.map +1 -0
- package/lib/Cloudflare/Flagship/index.d.ts +1 -0
- package/lib/Cloudflare/Flagship/index.d.ts.map +1 -1
- package/lib/Cloudflare/Flagship/index.js +1 -0
- package/lib/Cloudflare/Flagship/index.js.map +1 -1
- package/lib/Cloudflare/Images/Variant.d.ts.map +1 -1
- package/lib/Cloudflare/Images/Variant.js +4 -1
- package/lib/Cloudflare/Images/Variant.js.map +1 -1
- package/lib/Cloudflare/KV/NamespaceHttp.d.ts +16 -1
- package/lib/Cloudflare/KV/NamespaceHttp.d.ts.map +1 -1
- package/lib/Cloudflare/KV/NamespaceHttp.js +8 -2
- package/lib/Cloudflare/KV/NamespaceHttp.js.map +1 -1
- package/lib/Cloudflare/KV/NamespaceLocal.d.ts +22 -0
- package/lib/Cloudflare/KV/NamespaceLocal.d.ts.map +1 -0
- package/lib/Cloudflare/KV/NamespaceLocal.js +32 -0
- package/lib/Cloudflare/KV/NamespaceLocal.js.map +1 -0
- package/lib/Cloudflare/KV/ReadNamespaceHttp.d.ts +2 -2
- package/lib/Cloudflare/KV/ReadNamespaceHttp.d.ts.map +1 -1
- package/lib/Cloudflare/KV/ReadNamespaceHttp.js +5 -6
- package/lib/Cloudflare/KV/ReadNamespaceHttp.js.map +1 -1
- package/lib/Cloudflare/KV/ReadNamespaceLocal.d.ts +27 -0
- package/lib/Cloudflare/KV/ReadNamespaceLocal.d.ts.map +1 -0
- package/lib/Cloudflare/KV/ReadNamespaceLocal.js +30 -0
- package/lib/Cloudflare/KV/ReadNamespaceLocal.js.map +1 -0
- package/lib/Cloudflare/KV/ReadWriteNamespaceHttp.d.ts +3 -3
- package/lib/Cloudflare/KV/ReadWriteNamespaceHttp.d.ts.map +1 -1
- package/lib/Cloudflare/KV/ReadWriteNamespaceHttp.js +6 -6
- package/lib/Cloudflare/KV/ReadWriteNamespaceHttp.js.map +1 -1
- package/lib/Cloudflare/KV/ReadWriteNamespaceLocal.d.ts +34 -0
- package/lib/Cloudflare/KV/ReadWriteNamespaceLocal.d.ts.map +1 -0
- package/lib/Cloudflare/KV/ReadWriteNamespaceLocal.js +37 -0
- package/lib/Cloudflare/KV/ReadWriteNamespaceLocal.js.map +1 -0
- package/lib/Cloudflare/KV/WriteNamespaceHttp.d.ts +2 -2
- package/lib/Cloudflare/KV/WriteNamespaceHttp.d.ts.map +1 -1
- package/lib/Cloudflare/KV/WriteNamespaceHttp.js +5 -6
- package/lib/Cloudflare/KV/WriteNamespaceHttp.js.map +1 -1
- package/lib/Cloudflare/KV/WriteNamespaceLocal.d.ts +27 -0
- package/lib/Cloudflare/KV/WriteNamespaceLocal.d.ts.map +1 -0
- package/lib/Cloudflare/KV/WriteNamespaceLocal.js +30 -0
- package/lib/Cloudflare/KV/WriteNamespaceLocal.js.map +1 -0
- package/lib/Cloudflare/KV/index.d.ts +3 -0
- package/lib/Cloudflare/KV/index.d.ts.map +1 -1
- package/lib/Cloudflare/KV/index.js +3 -0
- package/lib/Cloudflare/KV/index.js.map +1 -1
- package/lib/Cloudflare/LoadBalancer/Monitor.d.ts.map +1 -1
- package/lib/Cloudflare/LoadBalancer/Monitor.js +4 -1
- package/lib/Cloudflare/LoadBalancer/Monitor.js.map +1 -1
- package/lib/Cloudflare/LoadBalancer/MonitorGroup.d.ts.map +1 -1
- package/lib/Cloudflare/LoadBalancer/MonitorGroup.js +4 -1
- package/lib/Cloudflare/LoadBalancer/MonitorGroup.js.map +1 -1
- package/lib/Cloudflare/LoadBalancer/Pool.d.ts.map +1 -1
- package/lib/Cloudflare/LoadBalancer/Pool.js +4 -1
- package/lib/Cloudflare/LoadBalancer/Pool.js.map +1 -1
- package/lib/Cloudflare/LocalRuntime.d.ts +14 -0
- package/lib/Cloudflare/LocalRuntime.d.ts.map +1 -1
- package/lib/Cloudflare/LocalRuntime.js +1 -0
- package/lib/Cloudflare/LocalRuntime.js.map +1 -1
- package/lib/Cloudflare/MagicNetworkMonitoring/Rule.d.ts.map +1 -1
- package/lib/Cloudflare/MagicNetworkMonitoring/Rule.js +4 -1
- package/lib/Cloudflare/MagicNetworkMonitoring/Rule.js.map +1 -1
- package/lib/Cloudflare/Pipelines/Pipeline.d.ts.map +1 -1
- package/lib/Cloudflare/Pipelines/Pipeline.js +8 -2
- package/lib/Cloudflare/Pipelines/Pipeline.js.map +1 -1
- package/lib/Cloudflare/Pipelines/Sink.d.ts.map +1 -1
- package/lib/Cloudflare/Pipelines/Sink.js +8 -2
- package/lib/Cloudflare/Pipelines/Sink.js.map +1 -1
- package/lib/Cloudflare/Pipelines/Stream.d.ts.map +1 -1
- package/lib/Cloudflare/Pipelines/Stream.js +4 -1
- package/lib/Cloudflare/Pipelines/Stream.js.map +1 -1
- package/lib/Cloudflare/Providers.js +14 -11
- package/lib/Cloudflare/Providers.js.map +1 -1
- package/lib/Cloudflare/Queues/Consumer.d.ts.map +1 -1
- package/lib/Cloudflare/Queues/Consumer.js +30 -3
- package/lib/Cloudflare/Queues/Consumer.js.map +1 -1
- package/lib/Cloudflare/Queues/Queue.d.ts.map +1 -1
- package/lib/Cloudflare/Queues/Queue.js +4 -1
- package/lib/Cloudflare/Queues/Queue.js.map +1 -1
- package/lib/Cloudflare/Queues/QueueHttp.d.ts +20 -1
- package/lib/Cloudflare/Queues/QueueHttp.d.ts.map +1 -1
- package/lib/Cloudflare/Queues/QueueHttp.js +2 -2
- package/lib/Cloudflare/Queues/QueueHttp.js.map +1 -1
- package/lib/Cloudflare/Queues/WriteQueueHttp.d.ts +9 -3
- package/lib/Cloudflare/Queues/WriteQueueHttp.d.ts.map +1 -1
- package/lib/Cloudflare/Queues/WriteQueueHttp.js +11 -6
- package/lib/Cloudflare/Queues/WriteQueueHttp.js.map +1 -1
- package/lib/Cloudflare/Queues/WriteQueueLocal.d.ts +36 -0
- package/lib/Cloudflare/Queues/WriteQueueLocal.d.ts.map +1 -0
- package/lib/Cloudflare/Queues/WriteQueueLocal.js +51 -0
- package/lib/Cloudflare/Queues/WriteQueueLocal.js.map +1 -0
- package/lib/Cloudflare/Queues/index.d.ts +1 -0
- package/lib/Cloudflare/Queues/index.d.ts.map +1 -1
- package/lib/Cloudflare/Queues/index.js +1 -0
- package/lib/Cloudflare/Queues/index.js.map +1 -1
- package/lib/Cloudflare/R2/Bucket.js +12 -3
- package/lib/Cloudflare/R2/Bucket.js.map +1 -1
- package/lib/Cloudflare/R2/BucketEventNotification.js +4 -1
- package/lib/Cloudflare/R2/BucketEventNotification.js.map +1 -1
- package/lib/Cloudflare/R2/BucketHttp.d.ts +15 -1
- package/lib/Cloudflare/R2/BucketHttp.d.ts.map +1 -1
- package/lib/Cloudflare/R2/BucketHttp.js +3 -3
- package/lib/Cloudflare/R2/BucketHttp.js.map +1 -1
- package/lib/Cloudflare/R2/BucketLocal.d.ts +21 -0
- package/lib/Cloudflare/R2/BucketLocal.d.ts.map +1 -0
- package/lib/Cloudflare/R2/BucketLocal.js +32 -0
- package/lib/Cloudflare/R2/BucketLocal.js.map +1 -0
- package/lib/Cloudflare/R2/DataCatalog.js +4 -1
- package/lib/Cloudflare/R2/DataCatalog.js.map +1 -1
- package/lib/Cloudflare/R2/ReadBucketHttp.d.ts +2 -2
- package/lib/Cloudflare/R2/ReadBucketHttp.d.ts.map +1 -1
- package/lib/Cloudflare/R2/ReadBucketHttp.js +4 -4
- package/lib/Cloudflare/R2/ReadBucketHttp.js.map +1 -1
- package/lib/Cloudflare/R2/ReadBucketLocal.d.ts +27 -0
- package/lib/Cloudflare/R2/ReadBucketLocal.d.ts.map +1 -0
- package/lib/Cloudflare/R2/ReadBucketLocal.js +30 -0
- package/lib/Cloudflare/R2/ReadBucketLocal.js.map +1 -0
- package/lib/Cloudflare/R2/ReadWriteBucketHttp.d.ts +2 -2
- package/lib/Cloudflare/R2/ReadWriteBucketHttp.d.ts.map +1 -1
- package/lib/Cloudflare/R2/ReadWriteBucketHttp.js +5 -4
- package/lib/Cloudflare/R2/ReadWriteBucketHttp.js.map +1 -1
- package/lib/Cloudflare/R2/ReadWriteBucketLocal.d.ts +30 -0
- package/lib/Cloudflare/R2/ReadWriteBucketLocal.d.ts.map +1 -0
- package/lib/Cloudflare/R2/ReadWriteBucketLocal.js +33 -0
- package/lib/Cloudflare/R2/ReadWriteBucketLocal.js.map +1 -0
- package/lib/Cloudflare/R2/WriteBucketHttp.d.ts +2 -2
- package/lib/Cloudflare/R2/WriteBucketHttp.d.ts.map +1 -1
- package/lib/Cloudflare/R2/WriteBucketHttp.js +4 -4
- package/lib/Cloudflare/R2/WriteBucketHttp.js.map +1 -1
- package/lib/Cloudflare/R2/WriteBucketLocal.d.ts +27 -0
- package/lib/Cloudflare/R2/WriteBucketLocal.d.ts.map +1 -0
- package/lib/Cloudflare/R2/WriteBucketLocal.js +30 -0
- package/lib/Cloudflare/R2/WriteBucketLocal.js.map +1 -0
- package/lib/Cloudflare/R2/index.d.ts +3 -0
- package/lib/Cloudflare/R2/index.d.ts.map +1 -1
- package/lib/Cloudflare/R2/index.js +3 -0
- package/lib/Cloudflare/R2/index.js.map +1 -1
- package/lib/Cloudflare/Rum/Rule.d.ts.map +1 -1
- package/lib/Cloudflare/Rum/Rule.js +4 -1
- package/lib/Cloudflare/Rum/Rule.js.map +1 -1
- package/lib/Cloudflare/Snippets/Snippet.d.ts.map +1 -1
- package/lib/Cloudflare/Snippets/Snippet.js +4 -1
- package/lib/Cloudflare/Snippets/Snippet.js.map +1 -1
- package/lib/Cloudflare/StateStore/Api.d.ts +2 -0
- package/lib/Cloudflare/StateStore/CredentialsFile.d.ts +42 -0
- package/lib/Cloudflare/StateStore/CredentialsFile.d.ts.map +1 -0
- package/lib/Cloudflare/StateStore/CredentialsFile.js +23 -0
- package/lib/Cloudflare/StateStore/CredentialsFile.js.map +1 -0
- package/lib/Cloudflare/StateStore/State.d.ts +2 -2
- package/lib/Cloudflare/StateStore/State.d.ts.map +1 -1
- package/lib/Cloudflare/StateStore/State.js +46 -9
- package/lib/Cloudflare/StateStore/State.js.map +1 -1
- package/lib/Cloudflare/Tags/ZoneResourceTags.d.ts.map +1 -1
- package/lib/Cloudflare/Tags/ZoneResourceTags.js +4 -1
- package/lib/Cloudflare/Tags/ZoneResourceTags.js.map +1 -1
- package/lib/Cloudflare/Tunnel/ReadTunnel.d.ts +3 -3
- package/lib/Cloudflare/Tunnel/ReadTunnel.d.ts.map +1 -1
- package/lib/Cloudflare/Tunnel/ReadTunnel.js +7 -8
- package/lib/Cloudflare/Tunnel/ReadTunnel.js.map +1 -1
- package/lib/Cloudflare/Tunnel/ReadTunnelLocal.d.ts +29 -0
- package/lib/Cloudflare/Tunnel/ReadTunnelLocal.d.ts.map +1 -0
- package/lib/Cloudflare/Tunnel/ReadTunnelLocal.js +30 -0
- package/lib/Cloudflare/Tunnel/ReadTunnelLocal.js.map +1 -0
- package/lib/Cloudflare/Tunnel/ReadWriteTunnel.d.ts +3 -3
- package/lib/Cloudflare/Tunnel/ReadWriteTunnel.d.ts.map +1 -1
- package/lib/Cloudflare/Tunnel/ReadWriteTunnel.js +4 -4
- package/lib/Cloudflare/Tunnel/ReadWriteTunnel.js.map +1 -1
- package/lib/Cloudflare/Tunnel/ReadWriteTunnelLocal.d.ts +35 -0
- package/lib/Cloudflare/Tunnel/ReadWriteTunnelLocal.d.ts.map +1 -0
- package/lib/Cloudflare/Tunnel/ReadWriteTunnelLocal.js +36 -0
- package/lib/Cloudflare/Tunnel/ReadWriteTunnelLocal.js.map +1 -0
- package/lib/Cloudflare/Tunnel/TunnelBinding.d.ts +17 -1
- package/lib/Cloudflare/Tunnel/TunnelBinding.d.ts.map +1 -1
- package/lib/Cloudflare/Tunnel/TunnelBinding.js +7 -1
- package/lib/Cloudflare/Tunnel/TunnelBinding.js.map +1 -1
- package/lib/Cloudflare/Tunnel/TunnelLocalBinding.d.ts +19 -0
- package/lib/Cloudflare/Tunnel/TunnelLocalBinding.d.ts.map +1 -0
- package/lib/Cloudflare/Tunnel/TunnelLocalBinding.js +29 -0
- package/lib/Cloudflare/Tunnel/TunnelLocalBinding.js.map +1 -0
- package/lib/Cloudflare/Tunnel/WarpConnector.d.ts +3 -3
- package/lib/Cloudflare/Tunnel/WarpConnector.d.ts.map +1 -1
- package/lib/Cloudflare/Tunnel/WarpConnector.js +7 -4
- package/lib/Cloudflare/Tunnel/WarpConnector.js.map +1 -1
- package/lib/Cloudflare/Tunnel/WriteTunnel.d.ts +3 -3
- package/lib/Cloudflare/Tunnel/WriteTunnel.d.ts.map +1 -1
- package/lib/Cloudflare/Tunnel/WriteTunnel.js +7 -8
- package/lib/Cloudflare/Tunnel/WriteTunnel.js.map +1 -1
- package/lib/Cloudflare/Tunnel/WriteTunnelLocal.d.ts +29 -0
- package/lib/Cloudflare/Tunnel/WriteTunnelLocal.d.ts.map +1 -0
- package/lib/Cloudflare/Tunnel/WriteTunnelLocal.js +30 -0
- package/lib/Cloudflare/Tunnel/WriteTunnelLocal.js.map +1 -0
- package/lib/Cloudflare/Tunnel/index.d.ts +3 -0
- package/lib/Cloudflare/Tunnel/index.d.ts.map +1 -1
- package/lib/Cloudflare/Tunnel/index.js +3 -0
- package/lib/Cloudflare/Tunnel/index.js.map +1 -1
- package/lib/Cloudflare/UrlNormalization/UrlNormalization.d.ts.map +1 -1
- package/lib/Cloudflare/UrlNormalization/UrlNormalization.js +7 -1
- package/lib/Cloudflare/UrlNormalization/UrlNormalization.js.map +1 -1
- package/lib/Cloudflare/Vectorize/SearchIndexHttpClient.d.ts +30 -0
- package/lib/Cloudflare/Vectorize/SearchIndexHttpClient.d.ts.map +1 -0
- package/lib/Cloudflare/Vectorize/SearchIndexHttpClient.js +100 -0
- package/lib/Cloudflare/Vectorize/SearchIndexHttpClient.js.map +1 -0
- package/lib/Cloudflare/Vectorize/SearchIndexLocal.d.ts +42 -0
- package/lib/Cloudflare/Vectorize/SearchIndexLocal.d.ts.map +1 -0
- package/lib/Cloudflare/Vectorize/SearchIndexLocal.js +58 -0
- package/lib/Cloudflare/Vectorize/SearchIndexLocal.js.map +1 -0
- package/lib/Cloudflare/Vectorize/index.d.ts +1 -0
- package/lib/Cloudflare/Vectorize/index.d.ts.map +1 -1
- package/lib/Cloudflare/Vectorize/index.js +1 -0
- package/lib/Cloudflare/Vectorize/index.js.map +1 -1
- package/lib/Cloudflare/WaitingRoom/Settings.d.ts.map +1 -1
- package/lib/Cloudflare/WaitingRoom/Settings.js +7 -1
- package/lib/Cloudflare/WaitingRoom/Settings.js.map +1 -1
- package/lib/Cloudflare/Website/Vite.d.ts +19 -0
- package/lib/Cloudflare/Website/Vite.d.ts.map +1 -1
- package/lib/Cloudflare/Website/Vite.js +20 -0
- package/lib/Cloudflare/Website/Vite.js.map +1 -1
- package/lib/Cloudflare/Workers/BrowserHttpClient.d.ts +32 -0
- package/lib/Cloudflare/Workers/BrowserHttpClient.d.ts.map +1 -0
- package/lib/Cloudflare/Workers/BrowserHttpClient.js +100 -0
- package/lib/Cloudflare/Workers/BrowserHttpClient.js.map +1 -0
- package/lib/Cloudflare/Workers/BrowserLocal.d.ts +37 -0
- package/lib/Cloudflare/Workers/BrowserLocal.d.ts.map +1 -0
- package/lib/Cloudflare/Workers/BrowserLocal.js +53 -0
- package/lib/Cloudflare/Workers/BrowserLocal.js.map +1 -0
- package/lib/Cloudflare/Workers/Compatibility.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Compatibility.js +43 -7
- package/lib/Cloudflare/Workers/Compatibility.js.map +1 -1
- package/lib/Cloudflare/Workers/ConfigProvider.d.ts +8 -0
- package/lib/Cloudflare/Workers/ConfigProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/ConfigProvider.js +10 -1
- package/lib/Cloudflare/Workers/ConfigProvider.js.map +1 -1
- package/lib/Cloudflare/Workers/CronEventSource.d.ts +3 -2
- package/lib/Cloudflare/Workers/CronEventSource.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/CronEventSource.js.map +1 -1
- package/lib/Cloudflare/Workers/DurableObject.d.ts +137 -3
- package/lib/Cloudflare/Workers/DurableObject.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/DurableObject.js +141 -6
- package/lib/Cloudflare/Workers/DurableObject.js.map +1 -1
- package/lib/Cloudflare/Workers/DurableObjectBridge.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/DurableObjectBridge.js +86 -82
- package/lib/Cloudflare/Workers/DurableObjectBridge.js.map +1 -1
- package/lib/Cloudflare/Workers/HttpServer.d.ts +1 -4
- package/lib/Cloudflare/Workers/HttpServer.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/HttpServer.js +1 -3
- package/lib/Cloudflare/Workers/HttpServer.js.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts +2 -185
- package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js +74 -11
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js.map +1 -1
- package/lib/Cloudflare/Workers/ObservabilityDestination.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/ObservabilityDestination.js +4 -1
- package/lib/Cloudflare/Workers/ObservabilityDestination.js.map +1 -1
- package/lib/Cloudflare/Workers/Vite.d.ts +1 -1
- package/lib/Cloudflare/Workers/Vite.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Vite.js +81 -2
- package/lib/Cloudflare/Workers/Vite.js.map +1 -1
- package/lib/Cloudflare/Workers/Worker.d.ts +42 -6
- package/lib/Cloudflare/Workers/Worker.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Worker.js +10 -5
- package/lib/Cloudflare/Workers/Worker.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerAsyncBindings.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerAsyncBindings.js +26 -16
- package/lib/Cloudflare/Workers/WorkerAsyncBindings.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBinding.d.ts +22 -1
- package/lib/Cloudflare/Workers/WorkerBinding.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBinding.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBridge.d.ts +13 -5
- package/lib/Cloudflare/Workers/WorkerBridge.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBridge.js +133 -52
- package/lib/Cloudflare/Workers/WorkerBridge.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerProvider.d.ts +81 -0
- package/lib/Cloudflare/Workers/WorkerProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerProvider.js +476 -68
- package/lib/Cloudflare/Workers/WorkerProvider.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerRuntimeContext.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerRuntimeContext.js +11 -37
- package/lib/Cloudflare/Workers/WorkerRuntimeContext.js.map +1 -1
- package/lib/Cloudflare/Workers/cloudflare_workers.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/cloudflare_workers.js +10 -3
- package/lib/Cloudflare/Workers/cloudflare_workers.js.map +1 -1
- package/lib/Cloudflare/Workers/index.d.ts +1 -0
- package/lib/Cloudflare/Workers/index.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/index.js +1 -0
- package/lib/Cloudflare/Workers/index.js.map +1 -1
- package/lib/Cloudflare/Workflows/Workflow.d.ts +10 -7
- package/lib/Cloudflare/Workflows/Workflow.d.ts.map +1 -1
- package/lib/Cloudflare/Workflows/Workflow.js +38 -13
- package/lib/Cloudflare/Workflows/Workflow.js.map +1 -1
- package/lib/Cloudflare/Workflows/WorkflowBridge.d.ts.map +1 -1
- package/lib/Cloudflare/Workflows/WorkflowBridge.js +39 -37
- package/lib/Cloudflare/Workflows/WorkflowBridge.js.map +1 -1
- package/lib/Cloudflare/Workflows/WorkflowName.d.ts +11 -0
- package/lib/Cloudflare/Workflows/WorkflowName.d.ts.map +1 -0
- package/lib/Cloudflare/Workflows/WorkflowName.js +28 -0
- package/lib/Cloudflare/Workflows/WorkflowName.js.map +1 -0
- package/lib/Cloudflare/Zone/Hold.d.ts.map +1 -1
- package/lib/Cloudflare/Zone/Hold.js +7 -1
- package/lib/Cloudflare/Zone/Hold.js.map +1 -1
- package/lib/Command/Dev.d.ts +16 -6
- package/lib/Command/Dev.d.ts.map +1 -1
- package/lib/Command/Dev.js +37 -7
- package/lib/Command/Dev.js.map +1 -1
- package/lib/Diff.d.ts +16 -0
- package/lib/Diff.d.ts.map +1 -1
- package/lib/Diff.js +33 -0
- package/lib/Diff.js.map +1 -1
- package/lib/Docker/Container.js +4 -1
- package/lib/Docker/Container.js.map +1 -1
- package/lib/Drizzle/Postgres.d.ts +14 -13
- package/lib/Drizzle/Postgres.d.ts.map +1 -1
- package/lib/Drizzle/Postgres.js +39 -19
- package/lib/Drizzle/Postgres.js.map +1 -1
- package/lib/GitHub/AuthProvider.d.ts.map +1 -1
- package/lib/GitHub/AuthProvider.js +1 -1
- package/lib/GitHub/AuthProvider.js.map +1 -1
- package/lib/GitHub/Env.d.ts +20 -0
- package/lib/GitHub/Env.d.ts.map +1 -0
- package/lib/GitHub/Env.js +27 -0
- package/lib/GitHub/Env.js.map +1 -0
- package/lib/GitHub/Secrets.d.ts +1 -1
- package/lib/GitHub/Secrets.js +1 -1
- package/lib/GitHub/Variables.d.ts +1 -1
- package/lib/GitHub/Variables.js +1 -1
- 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/Http.d.ts +9 -0
- package/lib/Http.d.ts.map +1 -1
- package/lib/Http.js +9 -0
- package/lib/Http.js.map +1 -1
- package/lib/Local/RpcProviderProxy.js +1 -1
- package/lib/Local/RpcProviderProxy.js.map +1 -1
- package/lib/Local/RpcSerialization.d.ts.map +1 -1
- package/lib/Local/RpcSerialization.js +6 -2
- package/lib/Local/RpcSerialization.js.map +1 -1
- package/lib/Local/RpcSpawner.d.ts.map +1 -1
- package/lib/Local/RpcSpawner.js +14 -8
- package/lib/Local/RpcSpawner.js.map +1 -1
- package/lib/Neon/AuthProvider.d.ts.map +1 -1
- package/lib/Neon/AuthProvider.js +2 -2
- package/lib/Neon/AuthProvider.js.map +1 -1
- package/lib/Neon/Project.js +4 -1
- package/lib/Neon/Project.js.map +1 -1
- package/lib/Plan.d.ts.map +1 -1
- package/lib/Plan.js +37 -13
- package/lib/Plan.js.map +1 -1
- package/lib/Planetscale/AuthProvider.d.ts +26 -9
- package/lib/Planetscale/AuthProvider.d.ts.map +1 -1
- package/lib/Planetscale/AuthProvider.js +142 -11
- package/lib/Planetscale/AuthProvider.js.map +1 -1
- package/lib/Planetscale/Branch.d.ts.map +1 -1
- package/lib/Planetscale/Branch.js +4 -1
- package/lib/Planetscale/Branch.js.map +1 -1
- package/lib/Planetscale/Credentials.d.ts.map +1 -1
- package/lib/Planetscale/Credentials.js +14 -6
- package/lib/Planetscale/Credentials.js.map +1 -1
- package/lib/Planetscale/Database.d.ts +2 -1
- package/lib/Planetscale/Database.d.ts.map +1 -1
- package/lib/Planetscale/MySQL/MySQLClusterSize.d.ts +41 -3
- package/lib/Planetscale/MySQL/MySQLClusterSize.d.ts.map +1 -1
- package/lib/Planetscale/MySQL/MySQLClusterSize.js +88 -11
- package/lib/Planetscale/MySQL/MySQLClusterSize.js.map +1 -1
- package/lib/Planetscale/MySQL/MySQLDatabase.d.ts +14 -0
- package/lib/Planetscale/MySQL/MySQLDatabase.d.ts.map +1 -1
- package/lib/Planetscale/MySQL/MySQLDatabase.js +24 -11
- package/lib/Planetscale/MySQL/MySQLDatabase.js.map +1 -1
- package/lib/Planetscale/MySQL/MySQLMigrations.js +4 -1
- package/lib/Planetscale/MySQL/MySQLMigrations.js.map +1 -1
- package/lib/Planetscale/OAuthClient.d.ts +72 -0
- package/lib/Planetscale/OAuthClient.d.ts.map +1 -0
- package/lib/Planetscale/OAuthClient.js +227 -0
- package/lib/Planetscale/OAuthClient.js.map +1 -0
- package/lib/Planetscale/Postgres/PostgresClusterSize.d.ts.map +1 -1
- package/lib/Planetscale/Postgres/PostgresClusterSize.js +4 -1
- package/lib/Planetscale/Postgres/PostgresClusterSize.js.map +1 -1
- package/lib/Planetscale/Postgres/PostgresMigrations.js +4 -1
- package/lib/Planetscale/Postgres/PostgresMigrations.js.map +1 -1
- package/lib/Planetscale/Util.d.ts.map +1 -1
- package/lib/Planetscale/Util.js +4 -1
- package/lib/Planetscale/Util.js.map +1 -1
- package/lib/Platform.d.ts +2 -3
- package/lib/Platform.d.ts.map +1 -1
- package/lib/Platform.js +62 -3
- package/lib/Platform.js.map +1 -1
- package/lib/Provider.d.ts +35 -0
- package/lib/Provider.d.ts.map +1 -1
- package/lib/Provider.js.map +1 -1
- package/lib/Runtime.d.ts +23 -0
- package/lib/Runtime.d.ts.map +1 -1
- package/lib/Runtime.js +83 -0
- package/lib/Runtime.js.map +1 -1
- package/lib/RuntimeContext.d.ts +46 -0
- package/lib/RuntimeContext.d.ts.map +1 -1
- package/lib/RuntimeContext.js +60 -0
- package/lib/RuntimeContext.js.map +1 -1
- package/lib/Server/Process.d.ts +1 -1
- package/lib/Server/Process.d.ts.map +1 -1
- package/lib/Server/Process.js +8 -8
- package/lib/Server/Process.js.map +1 -1
- package/lib/Stack.js +1 -1
- package/lib/Stack.js.map +1 -1
- package/lib/State/HttpStateApi.d.ts +10 -10
- package/lib/State/HttpStateStore.js +5 -2
- package/lib/State/HttpStateStore.js.map +1 -1
- package/lib/Sync.d.ts.map +1 -1
- package/lib/Sync.js +3 -0
- package/lib/Sync.js.map +1 -1
- package/lib/Test/Alchemy.d.ts +74 -0
- package/lib/Test/Alchemy.d.ts.map +1 -0
- package/lib/Test/Alchemy.js +143 -0
- package/lib/Test/Alchemy.js.map +1 -0
- package/lib/Test/Http.d.ts.map +1 -1
- package/lib/Test/Http.js +8 -2
- package/lib/Test/Http.js.map +1 -1
- package/lib/Util/cached-function.d.ts +1 -1
- package/lib/Util/cached-function.d.ts.map +1 -1
- package/lib/Util/cached-function.js +2 -2
- package/lib/Util/cached-function.js.map +1 -1
- package/lib/Util/data.d.ts +6 -1
- package/lib/Util/data.d.ts.map +1 -1
- package/lib/Util/data.js.map +1 -1
- package/lib/Util/poll.js +1 -1
- package/lib/Util/poll.js.map +1 -1
- package/lib/Util/proxy-chain.js +3 -0
- package/lib/Util/proxy-chain.js.map +1 -1
- package/package.json +23 -23
- package/src/AWS/ACM/Certificate.ts +16 -12
- package/src/AWS/ApiGateway/common.ts +11 -8
- package/src/AWS/AuthProvider.ts +1 -4
- package/src/AWS/AutoScaling/AutoScalingGroup.ts +8 -6
- package/src/AWS/Bootstrap.ts +5 -6
- package/src/AWS/CloudFront/Distribution.ts +20 -16
- package/src/AWS/CloudFront/Function.ts +10 -6
- package/src/AWS/CloudFront/Invalidation.ts +4 -3
- package/src/AWS/CloudFront/KvEntries.ts +4 -3
- package/src/AWS/CloudFront/KvRoutesUpdate.ts +8 -6
- package/src/AWS/CloudFront/VpcOrigin.ts +12 -9
- package/src/AWS/CloudFront/common.ts +10 -6
- package/src/AWS/CloudWatch/AnomalyDetector.ts +4 -3
- package/src/AWS/CloudWatch/common.ts +1 -3
- package/src/AWS/DynamoDB/Table.ts +57 -47
- package/src/AWS/EC2/EIP.ts +6 -4
- package/src/AWS/EC2/EgressOnlyInternetGateway.ts +6 -4
- package/src/AWS/EC2/Instance.ts +12 -9
- package/src/AWS/EC2/InternetGateway.ts +18 -12
- package/src/AWS/EC2/NatGateway.ts +6 -10
- package/src/AWS/EC2/NetworkAcl.ts +6 -4
- package/src/AWS/EC2/NetworkAclEntry.ts +4 -3
- package/src/AWS/EC2/RouteTable.ts +12 -9
- package/src/AWS/EC2/RouteTableAssociation.ts +3 -5
- package/src/AWS/EC2/SecurityGroup.ts +10 -7
- package/src/AWS/EC2/Subnet.ts +15 -15
- package/src/AWS/EC2/Vpc.ts +12 -12
- package/src/AWS/EC2/VpcEndpoint.ts +6 -8
- package/src/AWS/EC2/hosted.ts +2 -1
- package/src/AWS/ECS/Service.ts +4 -3
- package/src/AWS/ECS/Task.ts +2 -1
- package/src/AWS/EKS/Addon.ts +8 -6
- package/src/AWS/EKS/Cluster.ts +4 -3
- package/src/AWS/ELBv2/TargetGroup.ts +4 -3
- package/src/AWS/ELBv2/TrustStore.ts +4 -3
- package/src/AWS/IAM/SAMLProvider.ts +4 -4
- package/src/AWS/IdentityCenter/AccountAssignment.ts +8 -6
- package/src/AWS/IdentityCenter/common.ts +1 -3
- package/src/AWS/KMS/Alias.ts +4 -3
- package/src/AWS/KMS/Key.ts +4 -3
- package/src/AWS/Kinesis/Stream.ts +2 -6
- package/src/AWS/Kinesis/StreamConsumer.ts +7 -12
- package/src/AWS/Lambda/Alias.ts +4 -3
- package/src/AWS/Lambda/EventInvokeConfig.ts +2 -6
- package/src/AWS/Lambda/EventSourceMapping.ts +10 -8
- package/src/AWS/Lambda/Function.ts +123 -77
- package/src/AWS/Lambda/MicrovmProvider.ts +18 -16
- package/src/AWS/Lambda/MicrovmRuntimeContext.ts +11 -38
- package/src/AWS/Lambda/NetworkConnector.ts +19 -15
- package/src/AWS/Lambda/RuntimeExtension.ts +46 -0
- package/src/AWS/Organizations/Account.ts +5 -6
- package/src/AWS/Organizations/common.ts +1 -3
- package/src/AWS/Providers.ts +22 -20
- package/src/AWS/RDS/DBCluster.ts +8 -6
- package/src/AWS/RDS/DBInstance.ts +8 -6
- package/src/AWS/RDS/DBProxy.ts +4 -3
- package/src/AWS/RDS/DBProxyEndpoint.ts +4 -3
- package/src/AWS/Route53/HealthCheck.ts +8 -6
- package/src/AWS/Route53/HostedZone.ts +8 -6
- package/src/AWS/Route53/Record.ts +4 -3
- package/src/AWS/S3/Bucket.ts +5 -4
- package/src/AWS/SQS/Queue.ts +26 -20
- package/src/AWS/StateStore/State.ts +5 -4
- package/src/AWS/Website/AssetDeployment.ts +10 -6
- package/src/Action.ts +39 -6
- package/src/ActionRuntimeContext.ts +68 -0
- package/src/Apply.ts +54 -8
- package/src/Auth/AuthProvider.ts +11 -0
- package/src/Auth/Lock.ts +5 -2
- package/src/Axiom/AuthProvider.ts +0 -3
- package/src/Bundle/PurePlugin.ts +34 -1
- package/src/Bundle/Vite.ts +67 -16
- package/src/Cli/LoggingCli.ts +7 -4
- package/src/Cli/commands/_shared.ts +171 -5
- package/src/Cli/commands/login.ts +91 -46
- package/src/Cli/commands/logs.ts +1 -0
- package/src/Cli/commands/nuke.ts +16 -44
- package/src/Cli/commands/profile.ts +67 -39
- package/src/Cli/commands/tail.ts +1 -0
- package/src/Cloudflare/AI/GatewayDynamicRouting.ts +38 -6
- package/src/Cloudflare/AI/LanguageModel.ts +25 -5
- package/src/Cloudflare/AI/QuerySearchLocal.ts +66 -0
- package/src/Cloudflare/AI/QuerySearchNamespaceLocal.ts +60 -0
- package/src/Cloudflare/AI/SearchHttpClient.ts +423 -0
- package/src/Cloudflare/AI/SearchInstance.ts +4 -3
- package/src/Cloudflare/AI/index.ts +2 -0
- package/src/Cloudflare/Access/Application.ts +7 -4
- package/src/Cloudflare/Alerting/Silence.ts +4 -3
- package/src/Cloudflare/Alerting/Webhook.ts +8 -6
- package/src/Cloudflare/Auth/AuthProvider.ts +55 -39
- package/src/Cloudflare/Auth/OAuthClient.ts +6 -7
- package/src/Cloudflare/Cache/RegionalTieredCache.ts +7 -4
- package/src/Cloudflare/Containers/ContainerApplication.ts +22 -2
- package/src/Cloudflare/Containers/ContainerBundle.ts +110 -34
- package/src/Cloudflare/Containers/ContainerPlatform.ts +14 -52
- package/src/Cloudflare/Containers/ContainerProvider.ts +73 -19
- package/src/Cloudflare/Containers/LocalContainerProvider.ts +78 -72
- package/src/Cloudflare/D1/QueryDatabaseHttpClient.ts +176 -0
- package/src/Cloudflare/D1/QueryDatabaseLocal.ts +66 -0
- package/src/Cloudflare/D1/index.ts +1 -0
- package/src/Cloudflare/DNS/DnsHttp.ts +24 -2
- package/src/Cloudflare/DNS/DnsLocal.ts +41 -0
- package/src/Cloudflare/DNS/ReadDnsHttp.ts +4 -5
- package/src/Cloudflare/DNS/ReadDnsLocal.ts +38 -0
- package/src/Cloudflare/DNS/ReadWriteDnsHttp.ts +5 -5
- package/src/Cloudflare/DNS/ReadWriteDnsLocal.ts +46 -0
- package/src/Cloudflare/DNS/WriteDnsHttp.ts +4 -5
- package/src/Cloudflare/DNS/WriteDnsLocal.ts +44 -0
- package/src/Cloudflare/DNS/index.ts +3 -0
- package/src/Cloudflare/Diagnostics/EndpointHealthcheck.ts +4 -3
- package/src/Cloudflare/Flagship/ReadFlagsHttpClient.ts +183 -0
- package/src/Cloudflare/Flagship/ReadFlagsLocal.ts +69 -0
- package/src/Cloudflare/Flagship/index.ts +1 -0
- package/src/Cloudflare/Images/Variant.ts +4 -3
- package/src/Cloudflare/KV/NamespaceHttp.ts +25 -2
- package/src/Cloudflare/KV/NamespaceLocal.ts +42 -0
- package/src/Cloudflare/KV/ReadNamespaceHttp.ts +7 -6
- package/src/Cloudflare/KV/ReadNamespaceLocal.ts +35 -0
- package/src/Cloudflare/KV/ReadWriteNamespaceHttp.ts +11 -6
- package/src/Cloudflare/KV/ReadWriteNamespaceLocal.ts +42 -0
- package/src/Cloudflare/KV/WriteNamespaceHttp.ts +7 -6
- package/src/Cloudflare/KV/WriteNamespaceLocal.ts +35 -0
- package/src/Cloudflare/KV/index.ts +3 -0
- package/src/Cloudflare/LoadBalancer/Monitor.ts +4 -3
- package/src/Cloudflare/LoadBalancer/MonitorGroup.ts +4 -3
- package/src/Cloudflare/LoadBalancer/Pool.ts +4 -3
- package/src/Cloudflare/LocalRuntime.ts +17 -0
- package/src/Cloudflare/MagicNetworkMonitoring/Rule.ts +4 -3
- package/src/Cloudflare/Pipelines/Pipeline.ts +8 -6
- package/src/Cloudflare/Pipelines/Sink.ts +8 -6
- package/src/Cloudflare/Pipelines/Stream.ts +4 -3
- package/src/Cloudflare/Providers.ts +21 -19
- package/src/Cloudflare/Queues/Consumer.ts +45 -9
- package/src/Cloudflare/Queues/Queue.ts +4 -3
- package/src/Cloudflare/Queues/QueueHttp.ts +24 -2
- package/src/Cloudflare/Queues/WriteQueueHttp.ts +16 -7
- package/src/Cloudflare/Queues/WriteQueueLocal.ts +64 -0
- package/src/Cloudflare/Queues/index.ts +1 -0
- package/src/Cloudflare/R2/Bucket.ts +12 -9
- package/src/Cloudflare/R2/BucketEventNotification.ts +4 -3
- package/src/Cloudflare/R2/BucketHttp.ts +20 -3
- package/src/Cloudflare/R2/BucketLocal.ts +47 -0
- package/src/Cloudflare/R2/DataCatalog.ts +4 -3
- package/src/Cloudflare/R2/ReadBucketHttp.ts +10 -5
- package/src/Cloudflare/R2/ReadBucketLocal.ts +33 -0
- package/src/Cloudflare/R2/ReadWriteBucketHttp.ts +11 -5
- package/src/Cloudflare/R2/ReadWriteBucketLocal.ts +36 -0
- package/src/Cloudflare/R2/WriteBucketHttp.ts +10 -5
- package/src/Cloudflare/R2/WriteBucketLocal.ts +33 -0
- package/src/Cloudflare/R2/index.ts +3 -0
- package/src/Cloudflare/Rum/Rule.ts +4 -3
- package/src/Cloudflare/Snippets/Snippet.ts +4 -3
- package/src/Cloudflare/StateStore/CredentialsFile.ts +48 -0
- package/src/Cloudflare/StateStore/State.ts +61 -25
- package/src/Cloudflare/Tags/ZoneResourceTags.ts +4 -3
- package/src/Cloudflare/Tunnel/ReadTunnel.ts +8 -9
- package/src/Cloudflare/Tunnel/ReadTunnelLocal.ts +33 -0
- package/src/Cloudflare/Tunnel/ReadWriteTunnel.ts +5 -5
- package/src/Cloudflare/Tunnel/ReadWriteTunnelLocal.ts +39 -0
- package/src/Cloudflare/Tunnel/TunnelBinding.ts +26 -2
- package/src/Cloudflare/Tunnel/TunnelLocalBinding.ts +38 -0
- package/src/Cloudflare/Tunnel/WarpConnector.ts +8 -5
- package/src/Cloudflare/Tunnel/WriteTunnel.ts +8 -9
- package/src/Cloudflare/Tunnel/WriteTunnelLocal.ts +33 -0
- package/src/Cloudflare/Tunnel/index.ts +3 -0
- package/src/Cloudflare/UrlNormalization/UrlNormalization.ts +7 -4
- package/src/Cloudflare/Vectorize/SearchIndexHttpClient.ts +183 -0
- package/src/Cloudflare/Vectorize/SearchIndexLocal.ts +70 -0
- package/src/Cloudflare/Vectorize/index.ts +1 -0
- package/src/Cloudflare/WaitingRoom/Settings.ts +7 -4
- package/src/Cloudflare/Website/Vite.ts +20 -0
- package/src/Cloudflare/Workers/BrowserHttpClient.ts +201 -0
- package/src/Cloudflare/Workers/BrowserLocal.ts +65 -0
- package/src/Cloudflare/Workers/Compatibility.ts +50 -7
- package/src/Cloudflare/Workers/ConfigProvider.ts +15 -1
- package/src/Cloudflare/Workers/CronEventSource.ts +3 -2
- package/src/Cloudflare/Workers/DurableObject.ts +227 -6
- package/src/Cloudflare/Workers/DurableObjectBridge.ts +38 -33
- package/src/Cloudflare/Workers/HttpServer.ts +1 -4
- package/src/Cloudflare/Workers/LocalWorkerProvider.ts +132 -26
- package/src/Cloudflare/Workers/ObservabilityDestination.ts +4 -3
- package/src/Cloudflare/Workers/Vite.ts +93 -11
- package/src/Cloudflare/Workers/Worker.ts +46 -6
- package/src/Cloudflare/Workers/WorkerAsyncBindings.ts +33 -21
- package/src/Cloudflare/Workers/WorkerBinding.ts +20 -1
- package/src/Cloudflare/Workers/WorkerBridge.ts +239 -108
- package/src/Cloudflare/Workers/WorkerProvider.ts +689 -135
- package/src/Cloudflare/Workers/WorkerRuntimeContext.ts +14 -45
- package/src/Cloudflare/Workers/cloudflare_workers.ts +20 -12
- package/src/Cloudflare/Workers/index.ts +1 -0
- package/src/Cloudflare/Workflows/Workflow.ts +54 -20
- package/src/Cloudflare/Workflows/WorkflowBridge.ts +19 -23
- package/src/Cloudflare/Workflows/WorkflowName.ts +41 -0
- package/src/Cloudflare/Zone/Hold.ts +7 -4
- package/src/Command/Dev.ts +42 -10
- package/src/Diff.ts +33 -0
- package/src/Docker/Container.ts +4 -1
- package/src/Drizzle/Postgres.ts +51 -23
- package/src/GitHub/AuthProvider.ts +0 -3
- package/src/GitHub/Env.ts +57 -0
- package/src/GitHub/Secrets.ts +1 -1
- package/src/GitHub/Variables.ts +1 -1
- package/src/GitHub/index.ts +1 -0
- package/src/Http.ts +11 -0
- package/src/Local/RpcProviderProxy.ts +1 -1
- package/src/Local/RpcSerialization.ts +6 -2
- package/src/Local/RpcSpawner.ts +21 -8
- package/src/Neon/AuthProvider.ts +1 -4
- package/src/Neon/Project.ts +2 -2
- package/src/Plan.ts +43 -13
- package/src/Planetscale/AuthProvider.ts +267 -27
- package/src/Planetscale/Branch.ts +4 -3
- package/src/Planetscale/Credentials.ts +18 -6
- package/src/Planetscale/Database.ts +2 -1
- package/src/Planetscale/MySQL/MySQLClusterSize.ts +120 -21
- package/src/Planetscale/MySQL/MySQLDatabase.ts +84 -44
- package/src/Planetscale/MySQL/MySQLMigrations.ts +4 -3
- package/src/Planetscale/OAuthClient.ts +307 -0
- package/src/Planetscale/Postgres/PostgresClusterSize.ts +4 -3
- package/src/Planetscale/Postgres/PostgresMigrations.ts +4 -3
- package/src/Planetscale/Util.ts +4 -3
- package/src/Platform.ts +83 -7
- package/src/Provider.ts +35 -0
- package/src/Runtime.ts +92 -0
- package/src/RuntimeContext.ts +79 -0
- package/src/Server/Process.ts +11 -18
- package/src/Stack.ts +1 -1
- package/src/State/HttpStateStore.ts +5 -5
- package/src/Sync.ts +3 -0
- package/src/Test/Alchemy.ts +282 -0
- package/src/Test/Http.ts +8 -6
- package/src/Util/cached-function.ts +5 -5
- package/src/Util/data.ts +14 -5
- package/src/Util/poll.ts +1 -1
- package/src/Util/proxy-chain.ts +3 -0
- package/lib/ExecutionContext.d.ts +0 -18
- package/lib/ExecutionContext.d.ts.map +0 -1
- package/lib/ExecutionContext.js +0 -10
- package/lib/ExecutionContext.js.map +0 -1
- package/src/ExecutionContext.ts +0 -18
package/bin/exec.js
CHANGED
|
@@ -8,10 +8,14 @@ import * as FileSystem from "effect/FileSystem";
|
|
|
8
8
|
import * as Path$1 from "effect/Path";
|
|
9
9
|
import { Path } from "effect/Path";
|
|
10
10
|
import * as Redacted from "effect/Redacted";
|
|
11
|
+
import * as path$1 from "pathe";
|
|
11
12
|
import path from "pathe";
|
|
12
13
|
import * as Config from "effect/Config";
|
|
14
|
+
import * as NodeOs from "node:os";
|
|
13
15
|
import os from "node:os";
|
|
14
16
|
import * as Semaphore from "effect/Semaphore";
|
|
17
|
+
import { lock } from "@alchemy.run/node-utils/lockfile";
|
|
18
|
+
import * as fs from "node:fs/promises";
|
|
15
19
|
import { newWebSocketRpcSession } from "capnweb";
|
|
16
20
|
import * as Cache from "effect/Cache";
|
|
17
21
|
import * as HttpBody from "effect/unstable/http/HttpBody";
|
|
@@ -27,6 +31,7 @@ import { SingleShotGen } from "effect/Utils";
|
|
|
27
31
|
import * as Effectable from "effect/Effectable";
|
|
28
32
|
import "effect/Predicate";
|
|
29
33
|
import "effect/Record";
|
|
34
|
+
import http from "node:http";
|
|
30
35
|
import * as Cause from "effect/Cause";
|
|
31
36
|
import * as Exit from "effect/Exit";
|
|
32
37
|
import * as Stream from "effect/Stream";
|
|
@@ -38,6 +43,22 @@ import * as Metric from "effect/Metric";
|
|
|
38
43
|
import * as Argument from "effect/unstable/cli/Argument";
|
|
39
44
|
import * as CliError from "effect/unstable/cli/CliError";
|
|
40
45
|
import { pathToFileURL } from "node:url";
|
|
46
|
+
import * as DistilledAuth from "@distilled.cloud/aws/Auth";
|
|
47
|
+
import { Credentials } from "@distilled.cloud/aws/Credentials";
|
|
48
|
+
import * as STS from "@distilled.cloud/aws/sts";
|
|
49
|
+
import * as Match from "effect/Match";
|
|
50
|
+
import { ChildProcess } from "effect/unstable/process";
|
|
51
|
+
import * as NodeCrypto from "node:crypto";
|
|
52
|
+
import crypto$1 from "node:crypto";
|
|
53
|
+
import * as p from "@clack/prompts";
|
|
54
|
+
import * as Region from "@distilled.cloud/aws/Region";
|
|
55
|
+
import { DEFAULT_API_BASE_URL } from "@distilled.cloud/axiom/Credentials";
|
|
56
|
+
import * as cfAccounts from "@distilled.cloud/cloudflare/accounts";
|
|
57
|
+
import * as CfCredentialsModule from "@distilled.cloud/cloudflare/Credentials";
|
|
58
|
+
import * as ChildProcess$1 from "effect/unstable/process/ChildProcess";
|
|
59
|
+
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner";
|
|
60
|
+
import * as PsCredentialsModule from "@distilled.cloud/planetscale/Credentials";
|
|
61
|
+
import { listOrganizations } from "@distilled.cloud/planetscale/Operations";
|
|
41
62
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
42
63
|
import { Box, Text, render, useApp, useInput } from "ink";
|
|
43
64
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
@@ -63,9 +84,9 @@ var AlchemyContext, AlchemyContextLive;
|
|
|
63
84
|
var init_AlchemyContext = __esm({ "lib/AlchemyContext.js": (() => {
|
|
64
85
|
AlchemyContext = class extends EffectContext.Service()("alchemy/Context") {};
|
|
65
86
|
AlchemyContextLive = Layer.effect(AlchemyContext, Effect.gen(function* () {
|
|
66
|
-
const fs = yield* FileSystem.FileSystem;
|
|
87
|
+
const fs$1 = yield* FileSystem.FileSystem;
|
|
67
88
|
const dir = (yield* Path$1.Path).join(process.cwd(), ".alchemy");
|
|
68
|
-
yield* fs.makeDirectory(dir, { recursive: true });
|
|
89
|
+
yield* fs$1.makeDirectory(dir, { recursive: true });
|
|
69
90
|
return {
|
|
70
91
|
dotAlchemy: dir,
|
|
71
92
|
updateStateStore: false,
|
|
@@ -90,16 +111,90 @@ var init_interactive = __esm({ "lib/Util/interactive.js": (() => {
|
|
|
90
111
|
};
|
|
91
112
|
}) });
|
|
92
113
|
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region lib/Auth/Lock.js
|
|
116
|
+
var sanitizeLockKey, UNLOCKABLE_FS_CODES, withLock;
|
|
117
|
+
var init_Lock = __esm({ "lib/Auth/Lock.js": (() => {
|
|
118
|
+
init_Profile();
|
|
119
|
+
sanitizeLockKey = (key) => key.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
120
|
+
UNLOCKABLE_FS_CODES = new Set([
|
|
121
|
+
"EROFS",
|
|
122
|
+
"EACCES",
|
|
123
|
+
"EPERM",
|
|
124
|
+
"ENOSPC"
|
|
125
|
+
]);
|
|
126
|
+
withLock = (key, effect) => {
|
|
127
|
+
const lockDir = path$1.join(rootDir, "lock");
|
|
128
|
+
const lockPath = path$1.join(lockDir, `${sanitizeLockKey(key)}.lock`);
|
|
129
|
+
return Effect.acquireUseRelease(Effect.promise(async () => {
|
|
130
|
+
try {
|
|
131
|
+
await fs.mkdir(lockDir, { recursive: true });
|
|
132
|
+
return await lock(lockPath, {
|
|
133
|
+
retries: {
|
|
134
|
+
retries: 2400,
|
|
135
|
+
minTimeout: 50,
|
|
136
|
+
maxTimeout: 50
|
|
137
|
+
},
|
|
138
|
+
stale: 3e4,
|
|
139
|
+
realpath: false,
|
|
140
|
+
onCompromised: (err) => {
|
|
141
|
+
console.warn(`auth lock compromised (continuing): ${err.message}`);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
} catch (err) {
|
|
145
|
+
const code = err.code;
|
|
146
|
+
if (code !== void 0 && UNLOCKABLE_FS_CODES.has(code)) {
|
|
147
|
+
console.warn(`auth lock unavailable (${code} at '${lockPath}') — continuing without cross-process locking`);
|
|
148
|
+
return async () => {};
|
|
149
|
+
}
|
|
150
|
+
if (err instanceof Error && err.message.includes("already being held")) throw new Error(`Timed out waiting for the alchemy auth lock '${lockPath}' — another alchemy process has held it for over 120s. If no other alchemy process is running, delete the lock file and retry.`, { cause: err });
|
|
151
|
+
throw err;
|
|
152
|
+
}
|
|
153
|
+
}), () => effect, (release) => Effect.promise(() => release().catch(() => {})));
|
|
154
|
+
};
|
|
155
|
+
}) });
|
|
156
|
+
|
|
93
157
|
//#endregion
|
|
94
158
|
//#region lib/Auth/AuthProvider.js
|
|
95
|
-
var interactiveMutex, AuthError, AuthProviders;
|
|
159
|
+
var AUTH_LANDING_HOST, AUTH_SUCCESS_URL, AUTH_ERROR_URL, LOCKED_METHODS, INTERACTIVE_METHODS, interactiveMutex, AuthError, AuthProviders, AuthProvider, AuthProviderLayer, getAuthProvider;
|
|
96
160
|
var init_AuthProvider = __esm({ "lib/Auth/AuthProvider.js": (() => {
|
|
161
|
+
init_Lock();
|
|
162
|
+
AUTH_LANDING_HOST = "https://alchemy.run";
|
|
163
|
+
AUTH_SUCCESS_URL = `${AUTH_LANDING_HOST}/auth/success`;
|
|
164
|
+
AUTH_ERROR_URL = `${AUTH_LANDING_HOST}/auth/error`;
|
|
165
|
+
LOCKED_METHODS = new Set([
|
|
166
|
+
"read",
|
|
167
|
+
"login",
|
|
168
|
+
"logout",
|
|
169
|
+
"configure"
|
|
170
|
+
]);
|
|
171
|
+
INTERACTIVE_METHODS = new Set(["login", "configure"]);
|
|
97
172
|
interactiveMutex = Semaphore.makeUnsafe(1);
|
|
98
173
|
AuthError = class extends Schema.TaggedErrorClass()("AuthError", {
|
|
99
174
|
message: Schema.String,
|
|
100
175
|
cause: Schema.optional(Schema.Defect())
|
|
101
176
|
}) {};
|
|
102
177
|
AuthProviders = class extends EffectContext.Service()("AuthProviders") {};
|
|
178
|
+
AuthProvider = () => (name, impl) => Effect.gen(function* () {
|
|
179
|
+
const ctx = yield* Effect.context();
|
|
180
|
+
const providers = yield* AuthProviders;
|
|
181
|
+
const service = yield* Effect.isEffect(impl) ? impl : Effect.succeed(impl);
|
|
182
|
+
return yield* Effect.sync(() => providers[name] = {
|
|
183
|
+
kind: "AuthProvider",
|
|
184
|
+
name,
|
|
185
|
+
...Object.fromEntries(Object.entries(service).map(([methodName, fn]) => [methodName, (...args) => {
|
|
186
|
+
let eff = fn(...args).pipe(Effect.provideContext(ctx));
|
|
187
|
+
if (LOCKED_METHODS.has(methodName)) {
|
|
188
|
+
const profileName = args[0];
|
|
189
|
+
eff = withLock(`${profileName}-${name}`, eff);
|
|
190
|
+
}
|
|
191
|
+
if (INTERACTIVE_METHODS.has(methodName)) eff = Semaphore.withPermits(interactiveMutex, 1)(eff);
|
|
192
|
+
return eff;
|
|
193
|
+
}]))
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
AuthProviderLayer = () => (name, impl) => Layer.effectDiscard(AuthProvider()(name, impl));
|
|
197
|
+
getAuthProvider = (name) => AuthProviders.use((registry) => registry[name] == null ? Effect.fail(new AuthError({ message: `AuthProvider '${name}' is not registered. Make sure its layer has been provided.` })) : Effect.succeed(registry[name]));
|
|
103
198
|
}) });
|
|
104
199
|
|
|
105
200
|
//#endregion
|
|
@@ -118,8 +213,8 @@ var init_Profile = __esm({ "lib/Auth/Profile.js": (() => {
|
|
|
118
213
|
});
|
|
119
214
|
AlchemyProfile = class extends EffectContext.Service()("Alchemy::Profile") {};
|
|
120
215
|
ProfileLive = Layer.effect(AlchemyProfile, Effect.gen(function* () {
|
|
121
|
-
const fs = yield* FileSystem.FileSystem;
|
|
122
|
-
const readConfig = fs.readFileString(configFilePath).pipe(Effect.flatMap((data) => Effect.try({
|
|
216
|
+
const fs$1 = yield* FileSystem.FileSystem;
|
|
217
|
+
const readConfig = fs$1.readFileString(configFilePath).pipe(Effect.flatMap((data) => Effect.try({
|
|
123
218
|
try: () => {
|
|
124
219
|
const parsed = JSON.parse(data);
|
|
125
220
|
if (parsed?.version !== CONFIG_VERSION) return emptyConfig();
|
|
@@ -127,7 +222,7 @@ var init_Profile = __esm({ "lib/Auth/Profile.js": (() => {
|
|
|
127
222
|
},
|
|
128
223
|
catch: emptyConfig
|
|
129
224
|
})), Effect.orElseSucceed(emptyConfig));
|
|
130
|
-
const writeConfig = (config) => fs.makeDirectory(path.dirname(configFilePath), { recursive: true }).pipe(Effect.flatMap(() => fs.writeFileString(configFilePath, JSON.stringify(config, null, 2))));
|
|
225
|
+
const writeConfig = (config) => fs$1.makeDirectory(path.dirname(configFilePath), { recursive: true }).pipe(Effect.flatMap(() => fs$1.writeFileString(configFilePath, JSON.stringify(config, null, 2))));
|
|
131
226
|
const getProfile = (name) => readConfig.pipe(Effect.map((config) => config.profiles[name]));
|
|
132
227
|
const setProfile = (name, profile$1) => readConfig.pipe(Effect.tap((config) => Effect.sync(() => config.profiles[name] = profile$1)), Effect.flatMap(writeConfig));
|
|
133
228
|
const deleteProfile = (name) => readConfig.pipe(Effect.flatMap((config) => {
|
|
@@ -153,16 +248,21 @@ var init_Profile = __esm({ "lib/Auth/Profile.js": (() => {
|
|
|
153
248
|
loadOrConfigure
|
|
154
249
|
};
|
|
155
250
|
}));
|
|
156
|
-
withProfileOverride = (base, profile$1) => {
|
|
157
|
-
if (profile$1 === void 0) return base;
|
|
251
|
+
withProfileOverride = (base$1, profile$1) => {
|
|
252
|
+
if (profile$1 === void 0) return base$1;
|
|
158
253
|
const overrides = { ALCHEMY_PROFILE: profile$1 };
|
|
159
|
-
const overrideProvider = ConfigProvider.make((path$
|
|
160
|
-
return ConfigProvider.orElse(base)(overrideProvider);
|
|
254
|
+
const overrideProvider = ConfigProvider.make((path$2) => Effect.succeed(path$2.length === 1 && typeof path$2[0] === "string" && path$2[0] in overrides ? ConfigProvider.makeValue(overrides[path$2[0]]) : void 0));
|
|
255
|
+
return ConfigProvider.orElse(base$1)(overrideProvider);
|
|
161
256
|
};
|
|
162
257
|
}) });
|
|
163
258
|
|
|
164
259
|
//#endregion
|
|
165
260
|
//#region lib/Auth/Credentials.js
|
|
261
|
+
function displayRedacted(r, visibleChars = 4) {
|
|
262
|
+
const raw = Redacted.value(r);
|
|
263
|
+
if (raw.length <= visibleChars) return "****";
|
|
264
|
+
return `${raw.slice(0, visibleChars)}****`;
|
|
265
|
+
}
|
|
166
266
|
var credentialsDirPath, profileCredentialsDirPath, credentialsFilePath, CredentialsStore, CredentialsStoreLive;
|
|
167
267
|
var init_Credentials = __esm({ "lib/Auth/Credentials.js": (() => {
|
|
168
268
|
init_Profile();
|
|
@@ -171,8 +271,8 @@ var init_Credentials = __esm({ "lib/Auth/Credentials.js": (() => {
|
|
|
171
271
|
credentialsFilePath = (profile$1, provider) => path.join(profileCredentialsDirPath(profile$1), `${provider}.json`);
|
|
172
272
|
CredentialsStore = class extends EffectContext.Service()("Alchemy::CredentialsStore") {};
|
|
173
273
|
CredentialsStoreLive = Layer.effect(CredentialsStore, Effect.gen(function* () {
|
|
174
|
-
const fs = yield* FileSystem.FileSystem;
|
|
175
|
-
const read = (profile$1, provider) => fs.readFileString(credentialsFilePath(profile$1, provider)).pipe(Effect.catch(() => Effect.succeed(void 0)), Effect.map((data) => {
|
|
274
|
+
const fs$1 = yield* FileSystem.FileSystem;
|
|
275
|
+
const read = (profile$1, provider) => fs$1.readFileString(credentialsFilePath(profile$1, provider)).pipe(Effect.catch(() => Effect.succeed(void 0)), Effect.map((data) => {
|
|
176
276
|
if (data === void 0) return void 0;
|
|
177
277
|
try {
|
|
178
278
|
return JSON.parse(data);
|
|
@@ -182,12 +282,12 @@ var init_Credentials = __esm({ "lib/Auth/Credentials.js": (() => {
|
|
|
182
282
|
}));
|
|
183
283
|
const write = (profile$1, provider, credentials) => {
|
|
184
284
|
const filePath = credentialsFilePath(profile$1, provider);
|
|
185
|
-
return fs.makeDirectory(path.dirname(filePath), { recursive: true }).pipe(Effect.flatMap(() => {
|
|
186
|
-
return fs.writeFileString(filePath, JSON.stringify(credentials, null, 2));
|
|
285
|
+
return fs$1.makeDirectory(path.dirname(filePath), { recursive: true }).pipe(Effect.flatMap(() => {
|
|
286
|
+
return fs$1.writeFileString(filePath, JSON.stringify(credentials, null, 2));
|
|
187
287
|
}));
|
|
188
288
|
};
|
|
189
|
-
const remove_ = (profile$1, provider) => fs.remove(credentialsFilePath(profile$1, provider)).pipe(Effect.catch(() => Effect.void));
|
|
190
|
-
const deleteProfile = (profile$1) => fs.remove(profileCredentialsDirPath(profile$1), { recursive: true }).pipe(Effect.catch(() => Effect.void));
|
|
289
|
+
const remove_ = (profile$1, provider) => fs$1.remove(credentialsFilePath(profile$1, provider)).pipe(Effect.catch(() => Effect.void));
|
|
290
|
+
const deleteProfile = (profile$1) => fs$1.remove(profileCredentialsDirPath(profile$1), { recursive: true }).pipe(Effect.catch(() => Effect.void));
|
|
191
291
|
return {
|
|
192
292
|
read,
|
|
193
293
|
write,
|
|
@@ -273,13 +373,13 @@ var init_FQN = __esm({ "lib/FQN.js": (() => {
|
|
|
273
373
|
FQN_SEPARATOR = "/";
|
|
274
374
|
toPath = (ns) => {
|
|
275
375
|
if (!ns) return [];
|
|
276
|
-
const path$
|
|
376
|
+
const path$2 = [];
|
|
277
377
|
let current = ns;
|
|
278
378
|
while (current) {
|
|
279
|
-
path$
|
|
379
|
+
path$2.unshift(current.Id);
|
|
280
380
|
current = current.Parent;
|
|
281
381
|
}
|
|
282
|
-
return path$
|
|
382
|
+
return path$2;
|
|
283
383
|
};
|
|
284
384
|
parseFqn = (fqn) => {
|
|
285
385
|
const parts = fqn.split(FQN_SEPARATOR);
|
|
@@ -384,7 +484,7 @@ function proxy(self) {
|
|
|
384
484
|
});
|
|
385
485
|
return proxy$1;
|
|
386
486
|
}
|
|
387
|
-
var inspect, of, asOutput, isOutput, ExprSymbol, exprKind, isExpr, BaseExpr, isResourceExpr, ResourceExpr, isPropExpr, PropExpr, isLiteralExpr, LiteralExpr, VoidExpr, isApplyExpr, ApplyExpr, isFlatMapExpr, FlatMapExpr, isEffectExpr, EffectExpr, isNamedExpr, NamedExpr, isAllExpr, AllExpr, isRefExpr, RefExpr, isStackRefExpr, StackRefExpr, stackRef, MissingSourceError, InvalidReferenceError, evaluate, hasOutputs, upstreamAny, upstream, resolveUpstream, toObject;
|
|
487
|
+
var inspect, of$1, asOutput, isOutput, ExprSymbol, exprKind, isExpr, BaseExpr, isResourceExpr, ResourceExpr, isPropExpr, PropExpr, isLiteralExpr, LiteralExpr, VoidExpr, isApplyExpr, ApplyExpr, isFlatMapExpr, FlatMapExpr, isEffectExpr, EffectExpr, isNamedExpr, NamedExpr, isAllExpr, AllExpr, isRefExpr, RefExpr, isStackRefExpr, StackRefExpr, stackRef, MissingSourceError, InvalidReferenceError, evaluate, hasOutputs, upstreamAny, upstream, resolveUpstream, toObject;
|
|
388
488
|
var init_Output = __esm({ "lib/Output.js": (() => {
|
|
389
489
|
init_Ref();
|
|
390
490
|
init_Resource();
|
|
@@ -394,7 +494,7 @@ var init_Output = __esm({ "lib/Output.js": (() => {
|
|
|
394
494
|
init_State();
|
|
395
495
|
init_data();
|
|
396
496
|
inspect = Symbol.for("nodejs.util.inspect.custom");
|
|
397
|
-
of = (resource) => {
|
|
497
|
+
of$1 = (resource) => {
|
|
398
498
|
if (isRef(resource)) {
|
|
399
499
|
const metadata = getRefMetadata(resource);
|
|
400
500
|
return new RefExpr(metadata.stack, metadata.stage, metadata.id, metadata.type !== void 0 ? { Type: metadata.type } : void 0);
|
|
@@ -579,7 +679,7 @@ var init_Output = __esm({ "lib/Output.js": (() => {
|
|
|
579
679
|
return `stackRef(${this.stack}${this.stage ? `, { stage: ${this.stage} }` : ""})`;
|
|
580
680
|
}
|
|
581
681
|
};
|
|
582
|
-
stackRef = (stack, options = {}) => Effect.succeed(new StackRefExpr(stack, options.stage));
|
|
682
|
+
stackRef = (stack, options$6 = {}) => Effect.succeed(new StackRefExpr(stack, options$6.stage));
|
|
583
683
|
MissingSourceError = class extends Data.TaggedError("MissingSourceError") {};
|
|
584
684
|
InvalidReferenceError = class extends Data.TaggedError("InvalidReferenceError") {};
|
|
585
685
|
evaluate = (expr, upstream$1) => Effect.gen(function* () {
|
|
@@ -717,10 +817,10 @@ var init_FileLogger = __esm({ "lib/Util/FileLogger.js": (() => {
|
|
|
717
817
|
init_AlchemyContext();
|
|
718
818
|
fileLogger = Effect.fn(function* (...segments) {
|
|
719
819
|
const { dotAlchemy } = yield* AlchemyContext;
|
|
720
|
-
const fs = yield* FileSystem.FileSystem;
|
|
721
|
-
const path$
|
|
722
|
-
const logFile = path$
|
|
723
|
-
yield* fs.makeDirectory(path$
|
|
820
|
+
const fs$1 = yield* FileSystem.FileSystem;
|
|
821
|
+
const path$2 = yield* Path;
|
|
822
|
+
const logFile = path$2.join(dotAlchemy, "log", ...segments);
|
|
823
|
+
yield* fs$1.makeDirectory(path$2.dirname(logFile), { recursive: true });
|
|
724
824
|
return yield* Logger.formatLogFmt.pipe(Logger.toFile(logFile, { flag: "a" }));
|
|
725
825
|
});
|
|
726
826
|
}) });
|
|
@@ -744,9 +844,9 @@ var init_PlatformServices = __esm({ "lib/Util/PlatformServices.js": (() => {
|
|
|
744
844
|
return Layer.merge(NodeServices.layer, NodeSocket.layerWebSocketConstructor);
|
|
745
845
|
}
|
|
746
846
|
});
|
|
747
|
-
runMain = (effect, options) => {
|
|
748
|
-
if (isBun) import("@effect/platform-bun/BunRuntime").then((BunRuntime) => BunRuntime.runMain(effect, options));
|
|
749
|
-
else import("@effect/platform-node/NodeRuntime").then((NodeRuntime) => NodeRuntime.runMain(effect, options));
|
|
847
|
+
runMain = (effect, options$6) => {
|
|
848
|
+
if (isBun) import("@effect/platform-bun/BunRuntime").then((BunRuntime) => BunRuntime.runMain(effect, options$6));
|
|
849
|
+
else import("@effect/platform-node/NodeRuntime").then((NodeRuntime) => NodeRuntime.runMain(effect, options$6));
|
|
750
850
|
};
|
|
751
851
|
}) });
|
|
752
852
|
|
|
@@ -761,31 +861,31 @@ var init_Stack = __esm({ "lib/Stack.js": (() => {
|
|
|
761
861
|
init_effect();
|
|
762
862
|
init_FileLogger();
|
|
763
863
|
init_PlatformServices();
|
|
764
|
-
Stack = Object.assign(taggedFunction(EffectContext.Service()("Stack"), (stackName, options, eff) => {
|
|
864
|
+
Stack = Object.assign(taggedFunction(EffectContext.Service()("Stack"), (stackName, options$6, eff) => {
|
|
765
865
|
if (!stackName) return (stackName$1) => Object.assign(stackRef(stackName$1).pipe(effectClass), {
|
|
766
866
|
stackName: stackName$1,
|
|
767
867
|
stage: createStageProxy(stackName$1),
|
|
768
|
-
state: options?.state,
|
|
769
|
-
providers: options?.providers,
|
|
770
|
-
make: (options$
|
|
868
|
+
state: options$6?.state,
|
|
869
|
+
providers: options$6?.providers,
|
|
870
|
+
make: (options$7, eff$1) => Stack(stackName$1, options$7, eff$1)
|
|
771
871
|
});
|
|
772
872
|
return eff.pipe(make$2({
|
|
773
873
|
name: stackName,
|
|
774
|
-
...options
|
|
874
|
+
...options$6
|
|
775
875
|
}), (eff$1) => Object.assign(eff$1, {
|
|
776
876
|
stackName,
|
|
777
877
|
stage: createStageProxy(stackName),
|
|
778
|
-
state: options?.state,
|
|
779
|
-
providers: options?.providers
|
|
878
|
+
state: options$6?.state,
|
|
879
|
+
providers: options$6?.providers
|
|
780
880
|
}));
|
|
781
881
|
}));
|
|
782
882
|
createStageProxy = (stackName) => new Proxy({}, { get: (_, stage$1) => stackRef(stackName, { stage: stage$1 }) });
|
|
783
883
|
StackName = Stack.use((stack) => Effect.succeed(stack.name));
|
|
784
|
-
make$2 = (options) => (effect) => Effect.scope.pipe(Effect.flatMap((scope) => {
|
|
785
|
-
if (options.state == null) return Effect.die(/* @__PURE__ */ new Error(`Stack "${options.name}" is missing a state store. Add a \`state\` layer to the stack options, e.g.:\n Alchemy.Stack("${options.name}", {\n providers: Cloudflare.providers(),\n state: Cloudflare.state(), // <-- required\n }, ...)\nSee https://
|
|
786
|
-
if (options.providers == null) return Effect.die(/* @__PURE__ */ new Error(`Stack "${options.name}" is missing a providers layer. Add a \`providers\` layer to the stack options, e.g.:\n Alchemy.Stack("${options.name}", {\n providers: Cloudflare.providers(), // <-- required\n state: Cloudflare.state(),\n }, ...)`));
|
|
787
|
-
return options.providers.pipe(Layer.provideMerge(options.state), Layer.provideMerge(Layer.effect(Stack, Stage.pipe(Effect.map((stage$1) => options.stack ?? {
|
|
788
|
-
name: options.name,
|
|
884
|
+
make$2 = (options$6) => (effect) => Effect.scope.pipe(Effect.flatMap((scope) => {
|
|
885
|
+
if (options$6.state == null) return Effect.die(/* @__PURE__ */ new Error(`Stack "${options$6.name}" is missing a state store. Add a \`state\` layer to the stack options, e.g.:\n Alchemy.Stack("${options$6.name}", {\n providers: Cloudflare.providers(),\n state: Cloudflare.state(), // <-- required\n }, ...)\nSee https://alchemy.run/state-store for available state stores.`));
|
|
886
|
+
if (options$6.providers == null) return Effect.die(/* @__PURE__ */ new Error(`Stack "${options$6.name}" is missing a providers layer. Add a \`providers\` layer to the stack options, e.g.:\n Alchemy.Stack("${options$6.name}", {\n providers: Cloudflare.providers(), // <-- required\n state: Cloudflare.state(),\n }, ...)`));
|
|
887
|
+
return options$6.providers.pipe(Layer.provideMerge(options$6.state), Layer.provideMerge(Layer.effect(Stack, Stage.pipe(Effect.map((stage$1) => options$6.stack ?? {
|
|
888
|
+
name: options$6.name,
|
|
789
889
|
stage: stage$1,
|
|
790
890
|
resources: {},
|
|
791
891
|
bindings: {},
|
|
@@ -867,12 +967,50 @@ const make$1 = Effect.fn(function* (spawnerUrl) {
|
|
|
867
967
|
requireServicesAt: "lookup"
|
|
868
968
|
});
|
|
869
969
|
return RpcProviderProxy.of({ get: Effect.fn(function* (mainUrl, providerName) {
|
|
870
|
-
const session = yield*
|
|
970
|
+
const session = yield* Cache.get(cache, mainUrl);
|
|
871
971
|
return unwrapRpcHandlers(yield* Effect.promise(() => session.getProvider(providerName)), ["tail"]);
|
|
872
972
|
}) });
|
|
873
973
|
});
|
|
874
974
|
const fromEnv = () => Layer.effect(RpcProviderProxy, Config.string(SPAWNER_URL_ENV_KEY).pipe(Effect.flatMap(make$1)));
|
|
875
975
|
|
|
976
|
+
//#endregion
|
|
977
|
+
//#region lib/ActionRuntimeContext.js
|
|
978
|
+
/**
|
|
979
|
+
* Runtime context bridge that lets an {@link Action} read Resource Outputs.
|
|
980
|
+
*
|
|
981
|
+
* Actions are peculiar: their init Effect runs at plan/stack-eval time (before
|
|
982
|
+
* any resource exists) while their body runs at apply time (after upstreams are
|
|
983
|
+
* materialized). To make `yield* db.databaseId` work inside an Action we split
|
|
984
|
+
* the {@link RuntimeContext} into two cooperating halves that share nothing but
|
|
985
|
+
* a sanitized key:
|
|
986
|
+
*
|
|
987
|
+
* - {@link makeCaptureContext} is provided while the init Effect runs. Its
|
|
988
|
+
* `set(key, output)` records the referenced {@link Output} (so the engine can
|
|
989
|
+
* add a dependency edge and later resolve it) and its `get(key)` hands back a
|
|
990
|
+
* *deferred* accessor — an Effect that re-reads whatever `RuntimeContext` is
|
|
991
|
+
* ambient when it actually runs.
|
|
992
|
+
* - {@link makeResolveContext} is provided around the Action body at apply
|
|
993
|
+
* time. Its `get(key)` returns the already-resolved value for that key.
|
|
994
|
+
*
|
|
995
|
+
* Because the accessor produced at init re-reads `RuntimeContext`, yielding it
|
|
996
|
+
* inside the body resolves against the apply-time context — no shared mutable
|
|
997
|
+
* state, no infinite recursion (the resolve context's `get` is terminal).
|
|
998
|
+
*/
|
|
999
|
+
const base = (id) => ({
|
|
1000
|
+
Type: "Action",
|
|
1001
|
+
id,
|
|
1002
|
+
env: {}
|
|
1003
|
+
});
|
|
1004
|
+
/**
|
|
1005
|
+
* Resolve context — provided around an Action body at apply time. `resolved`
|
|
1006
|
+
* maps each captured key to its value (already evaluated against the tracker).
|
|
1007
|
+
*/
|
|
1008
|
+
const makeResolveContext = (resolved) => ({
|
|
1009
|
+
...base("resolve"),
|
|
1010
|
+
set: (key) => Effect.succeed(key),
|
|
1011
|
+
get: (key) => Effect.succeed(resolved[key])
|
|
1012
|
+
});
|
|
1013
|
+
|
|
876
1014
|
//#endregion
|
|
877
1015
|
//#region lib/Diff.js
|
|
878
1016
|
init_Output();
|
|
@@ -885,6 +1023,30 @@ const _hasUnresolved = (value) => {
|
|
|
885
1023
|
if (typeof value === "object") return Object.values(value).some(_hasUnresolved);
|
|
886
1024
|
return false;
|
|
887
1025
|
};
|
|
1026
|
+
/**
|
|
1027
|
+
* Deeply replace every unresolved plan-time expression (an `Output`/`Expr`
|
|
1028
|
+
* or an un-evaluated `Effect`) with `undefined`, leaving resolved values
|
|
1029
|
+
* (including opaque `Redacted`/`Duration` instances) intact.
|
|
1030
|
+
*
|
|
1031
|
+
* Persisted resource state must only ever hold plain data. Durable (JSON)
|
|
1032
|
+
* state stores already enforce this implicitly — Output proxies are
|
|
1033
|
+
* function-typed, so `JSON.stringify` silently drops them — but the
|
|
1034
|
+
* in-memory store used by tests retains live proxies, which would later be
|
|
1035
|
+
* fed back into provider lifecycle operations as `olds` after an
|
|
1036
|
+
* interrupted apply (e.g. `read` during a destroy plan) and blow up on
|
|
1037
|
+
* first string coercion. Sanitizing at the commit boundary keeps both
|
|
1038
|
+
* store kinds consistent with the provider contract that `olds` is
|
|
1039
|
+
* resolved `Props`.
|
|
1040
|
+
*/
|
|
1041
|
+
const stripUnresolved = (value) => _stripUnresolved(value);
|
|
1042
|
+
const _stripUnresolved = (value) => {
|
|
1043
|
+
if (value == null || isPrimitive(value)) return value;
|
|
1044
|
+
if (isExpr(value) || Effect.isEffect(value)) return void 0;
|
|
1045
|
+
if (Redacted.isRedacted(value) || Duration.isDuration(value)) return value;
|
|
1046
|
+
if (Array.isArray(value)) return value.map(_stripUnresolved);
|
|
1047
|
+
if (typeof value === "object") return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, _stripUnresolved(item)]));
|
|
1048
|
+
return value;
|
|
1049
|
+
};
|
|
888
1050
|
const havePropsChanged = (oldProps, newProps) => hasOutputs(newProps) || JSON.stringify(canonicalize(oldProps ?? {}, false)) !== JSON.stringify(canonicalize(newProps ?? {}, false));
|
|
889
1051
|
const canonicalize = (value, stripNullish) => {
|
|
890
1052
|
if (stripNullish && value == null) return void 0;
|
|
@@ -1130,7 +1292,7 @@ init_Output();
|
|
|
1130
1292
|
init_Provider();
|
|
1131
1293
|
init_Resource();
|
|
1132
1294
|
init_sha256();
|
|
1133
|
-
const make = (stack, options = {}) => Effect.gen(function* () {
|
|
1295
|
+
const make = (stack, options$6 = {}) => Effect.gen(function* () {
|
|
1134
1296
|
const state = yield* yield* State;
|
|
1135
1297
|
const resources = Object.values(stack.resources);
|
|
1136
1298
|
const actions = Object.values(stack.actions ?? {});
|
|
@@ -1173,6 +1335,7 @@ const make = (stack, options = {}) => Effect.gen(function* () {
|
|
|
1173
1335
|
const newBindings = dedupeBindings(stack.bindings[resource.FQN] ?? []);
|
|
1174
1336
|
const diff = yield* provider.diff ? provider.diff({
|
|
1175
1337
|
id: resource.LogicalId,
|
|
1338
|
+
fqn: resource.FQN,
|
|
1176
1339
|
olds: oldProps,
|
|
1177
1340
|
instanceId: oldState.instanceId,
|
|
1178
1341
|
news: props,
|
|
@@ -1197,7 +1360,7 @@ const make = (stack, options = {}) => Effect.gen(function* () {
|
|
|
1197
1360
|
else if (Duration.isDuration(input) || Redacted.isRedacted(input)) return input;
|
|
1198
1361
|
else if (Array.isArray(input)) return yield* Effect.all(input.map(resolveInput), { concurrency: "unbounded" });
|
|
1199
1362
|
else if (isResource(input)) {
|
|
1200
|
-
const resolved = yield* resolveOutput(of(input));
|
|
1363
|
+
const resolved = yield* resolveOutput(of$1(input));
|
|
1201
1364
|
if (isResourceExpr(resolved) && resolved.stables) return yield* resolveInput(resolved.stables);
|
|
1202
1365
|
return yield* resolveInput(resolved);
|
|
1203
1366
|
} else if (typeof input === "object") return Object.fromEntries(yield* Effect.all(Object.entries(input).map(([key, value]) => resolveInput(value).pipe(Effect.map((value$1) => [key, value$1]))), { concurrency: "unbounded" }));
|
|
@@ -1253,7 +1416,7 @@ const make = (stack, options = {}) => Effect.gen(function* () {
|
|
|
1253
1416
|
const newResourceFqns = new Set(resources.map((r) => r.FQN));
|
|
1254
1417
|
const newActionFqns = new Set(actions.map((t) => t.FQN));
|
|
1255
1418
|
const newNodeFqns = new Set([...newResourceFqns, ...newActionFqns]);
|
|
1256
|
-
const newUpstreamDependencies = Object.fromEntries([...resources.map((resource) => [resource.FQN, Object.values(upstreamAny(resource.Props)).map((r) => r.FQN)]), ...actions.map((action) => [action.FQN, Object.values(upstreamAny(action.Input)).map((r) => r.FQN)])]);
|
|
1419
|
+
const newUpstreamDependencies = Object.fromEntries([...resources.map((resource) => [resource.FQN, Object.values(upstreamAny(resource.Props)).map((r) => r.FQN)]), ...actions.map((action) => [action.FQN, Array.from(new Set([...Object.values(upstreamAny(action.Input)).map((r) => r.FQN), ...Object.values(upstreamAny(action.Captures)).map((r) => r.FQN)]))])]);
|
|
1257
1420
|
const bindingUpstreamDependencies = Object.fromEntries(resources.map((resource) => [resource.FQN, Object.values(upstreamAny(stack.bindings[resource.FQN] ?? [])).map((r) => r.FQN)]));
|
|
1258
1421
|
const rawUpstreamDependencies = Object.fromEntries([...resources.map((resource) => {
|
|
1259
1422
|
const fqn = resource.FQN;
|
|
@@ -1305,6 +1468,7 @@ const make = (stack, options = {}) => Effect.gen(function* () {
|
|
|
1305
1468
|
const adoptInstanceId = yield* generateInstanceId();
|
|
1306
1469
|
const readResult = yield* provider.read({
|
|
1307
1470
|
id,
|
|
1471
|
+
fqn,
|
|
1308
1472
|
instanceId: adoptInstanceId,
|
|
1309
1473
|
olds: news,
|
|
1310
1474
|
output: void 0
|
|
@@ -1317,7 +1481,7 @@ const make = (stack, options = {}) => Effect.gen(function* () {
|
|
|
1317
1481
|
resourceType: resource.Type,
|
|
1318
1482
|
logicalId: id
|
|
1319
1483
|
});
|
|
1320
|
-
|
|
1484
|
+
oldState = {
|
|
1321
1485
|
status: "created",
|
|
1322
1486
|
fqn,
|
|
1323
1487
|
logicalId: id,
|
|
@@ -1331,13 +1495,6 @@ const make = (stack, options = {}) => Effect.gen(function* () {
|
|
|
1331
1495
|
downstream,
|
|
1332
1496
|
removalPolicy: resource.RemovalPolicy
|
|
1333
1497
|
};
|
|
1334
|
-
yield* state.set({
|
|
1335
|
-
stack: stackName,
|
|
1336
|
-
stage: stage$1,
|
|
1337
|
-
fqn,
|
|
1338
|
-
value: adoptedState
|
|
1339
|
-
});
|
|
1340
|
-
oldState = adoptedState;
|
|
1341
1498
|
forceUpdateAfterAdoption = true;
|
|
1342
1499
|
}
|
|
1343
1500
|
}
|
|
@@ -1359,6 +1516,7 @@ const make = (stack, options = {}) => Effect.gen(function* () {
|
|
|
1359
1516
|
if (provider.read) {
|
|
1360
1517
|
const attr = yield* provider.read({
|
|
1361
1518
|
id,
|
|
1519
|
+
fqn,
|
|
1362
1520
|
instanceId: oldState.instanceId,
|
|
1363
1521
|
olds: oldState.props,
|
|
1364
1522
|
output: oldState.attr
|
|
@@ -1376,13 +1534,14 @@ const make = (stack, options = {}) => Effect.gen(function* () {
|
|
|
1376
1534
|
const oldProps = oldState.props;
|
|
1377
1535
|
const diff = yield* asEffect(provider?.diff?.({
|
|
1378
1536
|
id,
|
|
1537
|
+
fqn,
|
|
1379
1538
|
olds: oldProps,
|
|
1380
1539
|
instanceId: oldState.instanceId,
|
|
1381
1540
|
output: oldState.attr,
|
|
1382
1541
|
news,
|
|
1383
1542
|
oldBindings,
|
|
1384
1543
|
newBindings
|
|
1385
|
-
}).pipe(providePlanScope(fqn, oldState.instanceId))).pipe(Effect.map((diff$1) => diff$1 ?? { action: havePropsChanged(oldProps, news) || bindingDiffs.some((b) => b.action !== "noop") ? "update" : "noop" }), Effect.map((diff$1) => options.force && diff$1.action === "noop" ? { action: "update" } : diff$1), Effect.map((diff$1) => forceUpdateAfterAdoption && diff$1.action === "noop" ? { action: "update" } : diff$1));
|
|
1544
|
+
}).pipe(providePlanScope(fqn, oldState.instanceId))).pipe(Effect.map((diff$1) => diff$1 ?? { action: havePropsChanged(oldProps, news) || bindingDiffs.some((b) => b.action !== "noop") ? "update" : "noop" }), Effect.map((diff$1) => options$6.force && diff$1.action === "noop" ? { action: "update" } : diff$1), Effect.map((diff$1) => forceUpdateAfterAdoption && diff$1.action === "noop" ? { action: "update" } : diff$1));
|
|
1386
1545
|
if (oldState.status === "creating") if (diff.action === "noop") return Node({
|
|
1387
1546
|
action: "create",
|
|
1388
1547
|
props: news,
|
|
@@ -1491,7 +1650,7 @@ const make = (stack, options = {}) => Effect.gen(function* () {
|
|
|
1491
1650
|
forced: false
|
|
1492
1651
|
}];
|
|
1493
1652
|
const prior = oldState;
|
|
1494
|
-
if (prior?.status === "ran" && prior.inputHash === inputHash && !options.force) return [fqn, {
|
|
1653
|
+
if (prior?.status === "ran" && prior.inputHash === inputHash && !options$6.force) return [fqn, {
|
|
1495
1654
|
kind: "action",
|
|
1496
1655
|
action: "noop",
|
|
1497
1656
|
def: action,
|
|
@@ -1505,7 +1664,7 @@ const make = (stack, options = {}) => Effect.gen(function* () {
|
|
|
1505
1664
|
input: action.Input,
|
|
1506
1665
|
state: prior,
|
|
1507
1666
|
downstream,
|
|
1508
|
-
forced: !!options.force
|
|
1667
|
+
forced: !!options$6.force
|
|
1509
1668
|
}];
|
|
1510
1669
|
})), { concurrency: "unbounded" }));
|
|
1511
1670
|
const cycleMembers = combinedCycleMembers;
|
|
@@ -1560,6 +1719,7 @@ const make = (stack, options = {}) => Effect.gen(function* () {
|
|
|
1560
1719
|
LogicalId: logicalId,
|
|
1561
1720
|
Type: persisted.actionType,
|
|
1562
1721
|
Input: persisted.input,
|
|
1722
|
+
Captures: {},
|
|
1563
1723
|
Run: () => void 0,
|
|
1564
1724
|
Output: void 0
|
|
1565
1725
|
}
|
|
@@ -1585,6 +1745,7 @@ const make = (stack, options = {}) => Effect.gen(function* () {
|
|
|
1585
1745
|
if (oldState.attr === void 0) {
|
|
1586
1746
|
if (provider.read) attr = yield* provider.read({
|
|
1587
1747
|
id: logicalId,
|
|
1748
|
+
fqn,
|
|
1588
1749
|
instanceId: oldState.instanceId,
|
|
1589
1750
|
olds: oldState.props,
|
|
1590
1751
|
output: oldState.attr
|
|
@@ -1640,7 +1801,7 @@ const make = (stack, options = {}) => Effect.gen(function* () {
|
|
|
1640
1801
|
"alchemy.stack": stack.name,
|
|
1641
1802
|
"alchemy.stage": stack.stage,
|
|
1642
1803
|
"alchemy.resources.count": Object.keys(stack.resources).length,
|
|
1643
|
-
"alchemy.force": !!options.force
|
|
1804
|
+
"alchemy.force": !!options$6.force
|
|
1644
1805
|
} }));
|
|
1645
1806
|
const providePlanScope = (fqn, instanceId) => (effect) => Effect.serviceOption(ArtifactStore).pipe(Effect.map(Option.getOrElse(createArtifactStore)), Effect.flatMap((store) => effect.pipe(Effect.provideService(Artifacts, makeScopedArtifacts(store, fqn)), Effect.provideService(InstanceId, instanceId))));
|
|
1646
1807
|
var DeleteResourceHasDownstreamDependencies = class extends Data.TaggedError("DeleteResourceHasDownstreamDependencies") {};
|
|
@@ -1648,6 +1809,7 @@ var UnsatisfiedResourceCycle = class extends Data.TaggedError("UnsatisfiedResour
|
|
|
1648
1809
|
|
|
1649
1810
|
//#endregion
|
|
1650
1811
|
//#region lib/Apply.js
|
|
1812
|
+
init_RuntimeContext();
|
|
1651
1813
|
init_Artifacts();
|
|
1652
1814
|
init_Cli();
|
|
1653
1815
|
init_Output();
|
|
@@ -1727,6 +1889,7 @@ const executeNode = (fqn, node, tracker, ready, readyStable, terminalStatuses, s
|
|
|
1727
1889
|
fqn,
|
|
1728
1890
|
value: {
|
|
1729
1891
|
...value,
|
|
1892
|
+
props: stripUnresolved(value.props),
|
|
1730
1893
|
namespace
|
|
1731
1894
|
}
|
|
1732
1895
|
});
|
|
@@ -1846,6 +2009,7 @@ const executeNode = (fqn, node, tracker, ready, readyStable, terminalStatuses, s
|
|
|
1846
2009
|
yield* report("pre-creating");
|
|
1847
2010
|
attr = yield* node.provider.precreate({
|
|
1848
2011
|
id: logicalId,
|
|
2012
|
+
fqn,
|
|
1849
2013
|
news: node.props,
|
|
1850
2014
|
session: scopedSession,
|
|
1851
2015
|
instanceId,
|
|
@@ -1879,6 +2043,7 @@ const executeNode = (fqn, node, tracker, ready, readyStable, terminalStatuses, s
|
|
|
1879
2043
|
const bindingOutputs = excludeDeletedBindings(yield* evaluate(node.bindings, outputs));
|
|
1880
2044
|
attr = yield* node.provider.reconcile({
|
|
1881
2045
|
id: logicalId,
|
|
2046
|
+
fqn,
|
|
1882
2047
|
news,
|
|
1883
2048
|
instanceId,
|
|
1884
2049
|
bindings: bindingOutputs,
|
|
@@ -1944,6 +2109,7 @@ const executeNode = (fqn, node, tracker, ready, readyStable, terminalStatuses, s
|
|
|
1944
2109
|
const bindingOutputs = excludeDeletedBindings(yield* evaluate(node.bindings, outputs));
|
|
1945
2110
|
const attr = yield* node.provider.reconcile({
|
|
1946
2111
|
id: logicalId,
|
|
2112
|
+
fqn,
|
|
1947
2113
|
news,
|
|
1948
2114
|
instanceId,
|
|
1949
2115
|
bindings: bindingOutputs,
|
|
@@ -2014,6 +2180,7 @@ const executeNode = (fqn, node, tracker, ready, readyStable, terminalStatuses, s
|
|
|
2014
2180
|
const retain = node.resource.RemovalPolicy === "retain";
|
|
2015
2181
|
if (old.attr !== void 0 && !retain) yield* node.provider.delete({
|
|
2016
2182
|
id: logicalId,
|
|
2183
|
+
fqn,
|
|
2017
2184
|
instanceId: old.instanceId,
|
|
2018
2185
|
olds: old.props,
|
|
2019
2186
|
output: old.attr,
|
|
@@ -2037,6 +2204,7 @@ const executeNode = (fqn, node, tracker, ready, readyStable, terminalStatuses, s
|
|
|
2037
2204
|
yield* report("pre-creating");
|
|
2038
2205
|
attr = yield* node.provider.precreate({
|
|
2039
2206
|
id: logicalId,
|
|
2207
|
+
fqn,
|
|
2040
2208
|
news: node.props,
|
|
2041
2209
|
session: scopedSession,
|
|
2042
2210
|
instanceId,
|
|
@@ -2072,6 +2240,7 @@ const executeNode = (fqn, node, tracker, ready, readyStable, terminalStatuses, s
|
|
|
2072
2240
|
const bindingOutputs = excludeDeletedBindings(yield* evaluate(node.bindings, outputs));
|
|
2073
2241
|
attr = yield* node.provider.reconcile({
|
|
2074
2242
|
id: logicalId,
|
|
2243
|
+
fqn,
|
|
2075
2244
|
news,
|
|
2076
2245
|
instanceId,
|
|
2077
2246
|
bindings: bindingOutputs,
|
|
@@ -2141,6 +2310,16 @@ const executeNode = (fqn, node, tracker, ready, readyStable, terminalStatuses, s
|
|
|
2141
2310
|
"alchemy.resource.logical_id": node.resource.LogicalId,
|
|
2142
2311
|
"alchemy.resource.action": node.action
|
|
2143
2312
|
} }));
|
|
2313
|
+
/**
|
|
2314
|
+
* Run an Action body, resolving any Outputs it captured via `yield* output`
|
|
2315
|
+
* during init against the current tracker and exposing them to the body through
|
|
2316
|
+
* the resolve {@link RuntimeContext}. See {@link makeCaptureContext}.
|
|
2317
|
+
*/
|
|
2318
|
+
const runAction = Effect.fn("apply.runAction")(function* (task, input, outputs) {
|
|
2319
|
+
const resolved = {};
|
|
2320
|
+
for (const [key, output] of Object.entries(task.Captures)) resolved[key] = yield* evaluate(output, outputs);
|
|
2321
|
+
return yield* task.Run(input).pipe(Effect.provideService(RuntimeContext, makeResolveContext(resolved)));
|
|
2322
|
+
});
|
|
2144
2323
|
const executeActionNode = (fqn, node, tracker, ready, readyStable, terminalStatuses, session, state, stackName, stage$1, getOutputs, waitForDeps, failures) => Effect.gen(function* () {
|
|
2145
2324
|
const task = node.def;
|
|
2146
2325
|
const logicalId = task.LogicalId;
|
|
@@ -2180,7 +2359,7 @@ const executeActionNode = (fqn, node, tracker, ready, readyStable, terminalStatu
|
|
|
2180
2359
|
return;
|
|
2181
2360
|
}
|
|
2182
2361
|
yield* report("pending");
|
|
2183
|
-
yield* waitForDeps(Object.keys(resolveUpstream(node.input)).filter((f) => f in readyStable));
|
|
2362
|
+
yield* waitForDeps([...new Set([...Object.keys(resolveUpstream(node.input)), ...Object.keys(upstreamAny(task.Captures))])].filter((f) => f in readyStable));
|
|
2184
2363
|
const outputs = getOutputs();
|
|
2185
2364
|
const resolvedInput = yield* evaluate(node.input, outputs);
|
|
2186
2365
|
const inputHashValue = yield* hashInput(resolvedInput);
|
|
@@ -2195,7 +2374,7 @@ const executeActionNode = (fqn, node, tracker, ready, readyStable, terminalStatu
|
|
|
2195
2374
|
downstream: node.downstream
|
|
2196
2375
|
});
|
|
2197
2376
|
yield* report("running");
|
|
2198
|
-
const result = yield* task
|
|
2377
|
+
const result = yield* runAction(task, resolvedInput, outputs);
|
|
2199
2378
|
yield* commit({
|
|
2200
2379
|
kind: "action",
|
|
2201
2380
|
status: "ran",
|
|
@@ -2270,6 +2449,7 @@ const converge = Effect.fn(function* (plan, tracker, terminalStatuses, session,
|
|
|
2270
2449
|
};
|
|
2271
2450
|
const attr = yield* node.provider.reconcile({
|
|
2272
2451
|
id: logicalId,
|
|
2452
|
+
fqn,
|
|
2273
2453
|
news: newProps,
|
|
2274
2454
|
instanceId,
|
|
2275
2455
|
bindings: newBindings,
|
|
@@ -2333,7 +2513,7 @@ const converge = Effect.fn(function* (plan, tracker, terminalStatuses, session,
|
|
|
2333
2513
|
downstream: node.downstream
|
|
2334
2514
|
}
|
|
2335
2515
|
});
|
|
2336
|
-
const result = yield* node.def
|
|
2516
|
+
const result = yield* runAction(node.def, newInput, outputs);
|
|
2337
2517
|
yield* state.set({
|
|
2338
2518
|
stack: stackName,
|
|
2339
2519
|
stage: stage$1,
|
|
@@ -2421,6 +2601,7 @@ const collectGarbage = Effect.fn(function* (plan, session) {
|
|
|
2421
2601
|
fqn,
|
|
2422
2602
|
value: {
|
|
2423
2603
|
...value,
|
|
2604
|
+
props: stripUnresolved(value.props),
|
|
2424
2605
|
namespace
|
|
2425
2606
|
}
|
|
2426
2607
|
});
|
|
@@ -2469,6 +2650,7 @@ const collectGarbage = Effect.fn(function* (plan, session) {
|
|
|
2469
2650
|
if (retainOldGeneration) yield* scopedSession.note("Retaining replaced resource (removal policy: retain)...");
|
|
2470
2651
|
if (attr !== void 0 && !retainOldGeneration) yield* provider.delete({
|
|
2471
2652
|
id: logicalId,
|
|
2653
|
+
fqn,
|
|
2472
2654
|
instanceId,
|
|
2473
2655
|
olds: props,
|
|
2474
2656
|
output: attr,
|
|
@@ -2537,13 +2719,1722 @@ const excludeDeletedBindings = (bindings) => bindings.flatMap(({ action, sid, da
|
|
|
2537
2719
|
data
|
|
2538
2720
|
}]);
|
|
2539
2721
|
|
|
2722
|
+
//#endregion
|
|
2723
|
+
//#region lib/Util/Clank.js
|
|
2724
|
+
var PromptCancelled = class extends Data.TaggedError("PromptCancelled") {};
|
|
2725
|
+
const retryIfCancelled = Effect.retry({ while: (e) => e instanceof PromptCancelled });
|
|
2726
|
+
/**
|
|
2727
|
+
* Wraps a clack prompt (which returns a `Promise<T | symbol>` where the
|
|
2728
|
+
* symbol indicates user cancellation) in an Effect.
|
|
2729
|
+
*
|
|
2730
|
+
* Returns `undefined` if the user cancels (Ctrl+C / Escape).
|
|
2731
|
+
*
|
|
2732
|
+
* Uses `Effect.callback` so fiber interruption propagates via the abort
|
|
2733
|
+
* signal to any async resources we own; the clack prompt itself is left
|
|
2734
|
+
* to resolve — its result is ignored after interruption.
|
|
2735
|
+
*/
|
|
2736
|
+
const prompt = (fn) => Effect.callback((resume, signal) => {
|
|
2737
|
+
let settled = false;
|
|
2738
|
+
fn().then((result) => {
|
|
2739
|
+
if (settled || signal.aborted) return;
|
|
2740
|
+
settled = true;
|
|
2741
|
+
if (p.isCancel(result)) resume(Effect.fail(new PromptCancelled()));
|
|
2742
|
+
else resume(Effect.succeed(result));
|
|
2743
|
+
}, (err) => {
|
|
2744
|
+
if (settled || signal.aborted) return;
|
|
2745
|
+
settled = true;
|
|
2746
|
+
resume(Effect.die(err));
|
|
2747
|
+
});
|
|
2748
|
+
});
|
|
2749
|
+
const success = (str) => Effect.sync(() => p.log.success(str));
|
|
2750
|
+
const warn = (str) => Effect.sync(() => p.log.warn(str));
|
|
2751
|
+
const info = (str) => Effect.sync(() => p.log.info(str));
|
|
2752
|
+
const text = (opts) => prompt(() => p.text(opts));
|
|
2753
|
+
const password = (opts) => prompt(() => p.password(opts));
|
|
2754
|
+
const select = (opts) => prompt(() => p.select(opts));
|
|
2755
|
+
const confirm = (opts) => prompt(() => p.confirm(opts));
|
|
2756
|
+
const multiselect = (opts) => prompt(() => p.multiselect(opts));
|
|
2757
|
+
/**
|
|
2758
|
+
* Open a URL in the user's default browser.
|
|
2759
|
+
*
|
|
2760
|
+
* On Windows, uses rundll32's FileProtocolHandler — a built-in shim that
|
|
2761
|
+
* opens URLs in the default browser. It accepts the URL as a direct
|
|
2762
|
+
* argument (no shell, no quoting of `&`). cmd.exe `start` would treat
|
|
2763
|
+
* `&` in OAuth URLs as a command separator, and `explorer.exe` treats
|
|
2764
|
+
* its arg as a path.
|
|
2765
|
+
*/
|
|
2766
|
+
const openUrl = (url) => Effect.gen(function* () {
|
|
2767
|
+
const [cmd, args] = process.platform === "win32" ? ["rundll32.exe", ["url.dll,FileProtocolHandler", url]] : process.platform === "darwin" ? ["open", [url]] : ["xdg-open", [url]];
|
|
2768
|
+
yield* (yield* ChildProcess.make(cmd, [...args], { shell: false })).exitCode;
|
|
2769
|
+
}).pipe(Effect.scoped);
|
|
2770
|
+
|
|
2771
|
+
//#endregion
|
|
2772
|
+
//#region lib/Auth/Env.js
|
|
2773
|
+
init_AuthProvider();
|
|
2774
|
+
const getEnv = (key) => Config.string(key).pipe(Effect.orElseSucceed(() => void 0));
|
|
2775
|
+
const getEnvRequired = (key) => Config.string(key).pipe(Effect.catch(() => Effect.fail(new AuthError({ message: `Missing required env: ${key}` }))));
|
|
2776
|
+
const getEnvRedacted = (key) => Config.redacted(key).pipe(Effect.orElseSucceed(() => void 0));
|
|
2777
|
+
const getEnvRedactedRequired = (key) => Config.redacted(key).pipe(Effect.catch(() => Effect.fail(new AuthError({ message: `Missing required env: ${key}` }))));
|
|
2778
|
+
const retryOnce = (self) => self.pipe(Effect.retry({
|
|
2779
|
+
times: 1,
|
|
2780
|
+
while: (e) => e instanceof PromptCancelled
|
|
2781
|
+
}), Effect.mapError((e) => new AuthError({
|
|
2782
|
+
message: "User cancelled prompt",
|
|
2783
|
+
cause: e
|
|
2784
|
+
})));
|
|
2785
|
+
|
|
2786
|
+
//#endregion
|
|
2787
|
+
//#region lib/AWS/Environment.js
|
|
2788
|
+
init_AuthProvider();
|
|
2789
|
+
init_Profile();
|
|
2790
|
+
const AWS_PROFILE = Config.string("AWS_PROFILE").pipe(Config.withDefault("default"));
|
|
2791
|
+
const AWS_REGION = Config.string("AWS_REGION");
|
|
2792
|
+
const AWS_ACCOUNT_ID = Config.string("AWS_ACCOUNT_ID");
|
|
2793
|
+
const AWS_ACCESS_KEY_ID = Config.string("AWS_ACCESS_KEY_ID");
|
|
2794
|
+
const AWS_SECRET_ACCESS_KEY = Config.redacted("AWS_SECRET_ACCESS_KEY");
|
|
2795
|
+
const AWS_SESSION_TOKEN = Config.redacted("AWS_SESSION_TOKEN");
|
|
2796
|
+
var AWSEnvironment = class AWSEnvironment extends EffectContext.Service()("AWS::Environment") {
|
|
2797
|
+
static current = AWSEnvironment.use((env) => env);
|
|
2798
|
+
kind = "Environment";
|
|
2799
|
+
};
|
|
2800
|
+
const Default = Layer.effect(AWSEnvironment, Effect.gen(function* () {
|
|
2801
|
+
const profile$1 = yield* AlchemyProfile;
|
|
2802
|
+
const auth = yield* getAuthProvider(AWS_AUTH_PROVIDER_NAME);
|
|
2803
|
+
const profileName = yield* ALCHEMY_PROFILE;
|
|
2804
|
+
const ci = yield* Config.boolean("CI").pipe(Config.withDefault(false));
|
|
2805
|
+
return yield* profile$1.loadOrConfigure(auth, profileName, { ci }).pipe(Effect.flatMap((config) => auth.read(profileName, config)), Effect.orDie, Effect.cached);
|
|
2806
|
+
})).pipe(Layer.orDie);
|
|
2807
|
+
|
|
2808
|
+
//#endregion
|
|
2809
|
+
//#region lib/AWS/Region.js
|
|
2810
|
+
const of = (region) => Layer.succeed(Region.Region, Effect.succeed(region));
|
|
2811
|
+
const CurrentRegion = Effect.suspend(() => AWSEnvironment.use((env) => Effect.flatMap(env, ({ region }) => Effect.succeed(region))));
|
|
2812
|
+
/**
|
|
2813
|
+
* Derive the AWS region from the surrounding {@link AWSEnvironment}.
|
|
2814
|
+
*/
|
|
2815
|
+
const fromEnvironment = Layer.effect(Region.Region, Effect.gen(function* () {
|
|
2816
|
+
const env = yield* AWSEnvironment;
|
|
2817
|
+
return Effect.map(env, (env$1) => env$1.region);
|
|
2818
|
+
}));
|
|
2819
|
+
|
|
2820
|
+
//#endregion
|
|
2821
|
+
//#region lib/AWS/AuthProvider.js
|
|
2822
|
+
init_AuthProvider();
|
|
2823
|
+
init_Credentials();
|
|
2824
|
+
const AWS_AUTH_PROVIDER_NAME = "AWS";
|
|
2825
|
+
const options$5 = [
|
|
2826
|
+
{
|
|
2827
|
+
value: "sso",
|
|
2828
|
+
label: "SSO",
|
|
2829
|
+
hint: "aws sso login — credentials loaded from AWS SSO cache"
|
|
2830
|
+
},
|
|
2831
|
+
{
|
|
2832
|
+
value: "env",
|
|
2833
|
+
label: "Environment Variables",
|
|
2834
|
+
hint: "AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY"
|
|
2835
|
+
},
|
|
2836
|
+
{
|
|
2837
|
+
value: "stored",
|
|
2838
|
+
label: "Stored",
|
|
2839
|
+
hint: "stored in ~/.alchemy/credentials"
|
|
2840
|
+
}
|
|
2841
|
+
];
|
|
2842
|
+
/**
|
|
2843
|
+
* Layer that registers the AWS {@link AuthProvider} into the
|
|
2844
|
+
* {@link AuthProviders} registry when built. Include this in the AWS
|
|
2845
|
+
* `providers()` layer so `alchemy login` can discover it.
|
|
2846
|
+
*/
|
|
2847
|
+
const AwsAuth = AuthProviderLayer()(AWS_AUTH_PROVIDER_NAME, Effect.gen(function* () {
|
|
2848
|
+
const store = yield* CredentialsStore;
|
|
2849
|
+
const getAccountId = ({ accessKeyId, secretAccessKey, sessionToken, region }) => STS.getCallerIdentity({}).pipe(Effect.provide(Layer.mergeAll(Layer.succeed(Credentials, Effect.succeed({
|
|
2850
|
+
accessKeyId,
|
|
2851
|
+
secretAccessKey,
|
|
2852
|
+
sessionToken
|
|
2853
|
+
})), of(region))), Effect.flatMap((self) => self.Account ? Effect.succeed(self.Account) : Effect.die(/* @__PURE__ */ new Error("No account ID found"))));
|
|
2854
|
+
const loginStored = Effect.fn(function* (profileName) {
|
|
2855
|
+
const accessKeyId = yield* text({
|
|
2856
|
+
message: "AWS Access Key ID",
|
|
2857
|
+
validate: (v) => v.length === 0 ? "Required" : void 0
|
|
2858
|
+
}).pipe(retryOnce);
|
|
2859
|
+
const secretAccessKey = yield* password({
|
|
2860
|
+
message: "AWS Secret Access Key",
|
|
2861
|
+
validate: (v) => v.length === 0 ? "Required" : void 0
|
|
2862
|
+
}).pipe(retryOnce);
|
|
2863
|
+
const sessionToken = yield* text({
|
|
2864
|
+
message: "AWS Session Token (optional — press Enter or Esc to skip)",
|
|
2865
|
+
placeholder: "(none)"
|
|
2866
|
+
}).pipe(Effect.catch(() => Effect.succeed("")));
|
|
2867
|
+
const region = yield* text({
|
|
2868
|
+
message: "AWS Region",
|
|
2869
|
+
placeholder: "us-east-1",
|
|
2870
|
+
defaultValue: "us-east-1"
|
|
2871
|
+
}).pipe(retryOnce);
|
|
2872
|
+
const accountId = yield* getAccountId({
|
|
2873
|
+
accessKeyId: Redacted.make(accessKeyId),
|
|
2874
|
+
secretAccessKey: Redacted.make(secretAccessKey),
|
|
2875
|
+
sessionToken: sessionToken ? Redacted.make(sessionToken) : void 0,
|
|
2876
|
+
region
|
|
2877
|
+
});
|
|
2878
|
+
yield* store.write(profileName, "aws", {
|
|
2879
|
+
accountId,
|
|
2880
|
+
accessKeyId,
|
|
2881
|
+
secretAccessKey,
|
|
2882
|
+
sessionToken,
|
|
2883
|
+
region
|
|
2884
|
+
});
|
|
2885
|
+
yield* success("AWS credentials saved.");
|
|
2886
|
+
return { method: "stored" };
|
|
2887
|
+
});
|
|
2888
|
+
const configureInteractive = (profileName) => select({
|
|
2889
|
+
message: "AWS authentication method",
|
|
2890
|
+
options: options$5
|
|
2891
|
+
}).pipe(Effect.flatMap((method) => Match.value(method).pipe(Match.when("env", () => Effect.succeed({ method: "env" })), Match.when("sso", () => Effect.gen(function* () {
|
|
2892
|
+
const config = {
|
|
2893
|
+
method: "sso",
|
|
2894
|
+
ssoProfile: (yield* text({
|
|
2895
|
+
message: "AWS profile name (from ~/.aws/config)",
|
|
2896
|
+
placeholder: "default",
|
|
2897
|
+
defaultValue: "default"
|
|
2898
|
+
})) ?? "default"
|
|
2899
|
+
};
|
|
2900
|
+
yield* loginSSO(config);
|
|
2901
|
+
return config;
|
|
2902
|
+
})), Match.when("stored", () => loginStored(profileName)), Match.exhaustive)));
|
|
2903
|
+
const configureCredentials = (profileName, ctx) => Effect.gen(function* () {
|
|
2904
|
+
if (ctx.ci) return { method: "env" };
|
|
2905
|
+
return yield* configureInteractive(profileName);
|
|
2906
|
+
}).pipe(Effect.mapError((e) => new AuthError({
|
|
2907
|
+
message: "failed to configure credentials",
|
|
2908
|
+
cause: e
|
|
2909
|
+
})));
|
|
2910
|
+
const resolveCredentials = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, Effect.fn(function* () {
|
|
2911
|
+
const accessKeyId = yield* getEnvRedactedRequired("AWS_ACCESS_KEY_ID");
|
|
2912
|
+
const secretAccessKey = yield* getEnvRedactedRequired("AWS_SECRET_ACCESS_KEY");
|
|
2913
|
+
const sessionToken = yield* getEnvRedacted("AWS_SESSION_TOKEN");
|
|
2914
|
+
const region = yield* getEnv("AWS_REGION").pipe(Effect.flatMap((region$1) => region$1 ? Effect.succeed(region$1) : getEnv("AWS_DEFAULT_REGION")));
|
|
2915
|
+
if (!region) return yield* Effect.fail(new AuthError({ message: "AWS region not found. Set AWS_REGION or AWS_DEFAULT_REGION." }));
|
|
2916
|
+
return {
|
|
2917
|
+
accountId: yield* getEnvRequired("AWS_ACCOUNT_ID").pipe(Effect.catch(() => getAccountId({
|
|
2918
|
+
accessKeyId,
|
|
2919
|
+
secretAccessKey,
|
|
2920
|
+
sessionToken,
|
|
2921
|
+
region
|
|
2922
|
+
}))),
|
|
2923
|
+
credentials: Effect.succeed({
|
|
2924
|
+
accessKeyId,
|
|
2925
|
+
secretAccessKey,
|
|
2926
|
+
sessionToken
|
|
2927
|
+
}),
|
|
2928
|
+
region,
|
|
2929
|
+
source: { type: "env" }
|
|
2930
|
+
};
|
|
2931
|
+
})), Match.when({ method: "stored" }, () => store.read(profileName, "aws").pipe(Effect.flatMap((creds) => creds == null ? Effect.fail(new AuthError({ message: "AWS stored credentials not found. Run: alchemy login --configure" })) : Effect.succeed({
|
|
2932
|
+
accountId: creds.accountId,
|
|
2933
|
+
credentials: Effect.succeed({
|
|
2934
|
+
accessKeyId: Redacted.make(creds.accessKeyId),
|
|
2935
|
+
secretAccessKey: Redacted.make(creds.secretAccessKey),
|
|
2936
|
+
sessionToken: creds.sessionToken ? Redacted.make(creds.sessionToken) : void 0
|
|
2937
|
+
}),
|
|
2938
|
+
region: creds.region,
|
|
2939
|
+
source: { type: "stored" }
|
|
2940
|
+
})), Effect.flatMap((creds) => creds.accountId ? Effect.succeed(creds) : creds.credentials.pipe(Effect.flatMap((resolved) => getAccountId({
|
|
2941
|
+
accessKeyId: resolved.accessKeyId,
|
|
2942
|
+
secretAccessKey: resolved.secretAccessKey,
|
|
2943
|
+
sessionToken: resolved.sessionToken,
|
|
2944
|
+
region: creds.region
|
|
2945
|
+
})), Effect.map((accountId) => ({
|
|
2946
|
+
...creds,
|
|
2947
|
+
accountId
|
|
2948
|
+
})), Effect.tap((creds$1) => creds$1.credentials.pipe(Effect.tap(({ accessKeyId, secretAccessKey, sessionToken }) => store.write(profileName, "aws", {
|
|
2949
|
+
accessKeyId: Redacted.value(accessKeyId),
|
|
2950
|
+
secretAccessKey: Redacted.value(secretAccessKey),
|
|
2951
|
+
sessionToken: sessionToken ? Redacted.value(sessionToken) : void 0,
|
|
2952
|
+
region: creds$1.region,
|
|
2953
|
+
accountId: creds$1.accountId
|
|
2954
|
+
})))))))), Match.when({ method: "sso" }, (config$1) => Effect.gen(function* () {
|
|
2955
|
+
const auth = yield* DistilledAuth.Default;
|
|
2956
|
+
const profile$1 = yield* auth.loadProfile(config$1.ssoProfile).pipe(Effect.catch(() => Effect.succeed(void 0)));
|
|
2957
|
+
return {
|
|
2958
|
+
accountId: profile$1?.sso_account_id,
|
|
2959
|
+
credentials: auth.loadProfileCredentials(config$1.ssoProfile).pipe(Effect.mapError((e) => new AuthError({
|
|
2960
|
+
message: "failed to load credentials",
|
|
2961
|
+
cause: e
|
|
2962
|
+
})), Effect.orDie),
|
|
2963
|
+
region: profile$1?.region,
|
|
2964
|
+
source: {
|
|
2965
|
+
type: "sso",
|
|
2966
|
+
details: config$1.ssoProfile
|
|
2967
|
+
}
|
|
2968
|
+
};
|
|
2969
|
+
})), Match.exhaustive).pipe(Effect.mapError((e) => new AuthError({
|
|
2970
|
+
message: "login failed",
|
|
2971
|
+
cause: e
|
|
2972
|
+
})));
|
|
2973
|
+
const prettyPrint = (profileName, config) => resolveCredentials(profileName, config).pipe(Effect.tap(Effect.fn(function* (creds) {
|
|
2974
|
+
const { accessKeyId, secretAccessKey, sessionToken } = yield* creds.credentials;
|
|
2975
|
+
yield* Console.log(` accessKeyId: ${displayRedacted(accessKeyId)}`);
|
|
2976
|
+
yield* Console.log(` secretAccessKey: ${displayRedacted(secretAccessKey)}`);
|
|
2977
|
+
if (sessionToken) yield* Console.log(` sessionToken: ${displayRedacted(sessionToken)}`);
|
|
2978
|
+
if (creds.region) yield* Console.log(` region: ${creds.region}`);
|
|
2979
|
+
yield* Console.log(` source: ${creds.source.details ? `${creds.source.type} - ${creds.source.details}` : creds.source.type}`);
|
|
2980
|
+
})));
|
|
2981
|
+
const logout = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, () => Effect.void), Match.when({ method: "sso" }, (config$1) => info(`AWS: running 'aws sso logout --profile ${config$1.ssoProfile}'...`).pipe(Effect.zip(runSsoCommand("logout", config$1.ssoProfile)), Effect.zip(clearDistilledSsoCache(config$1.ssoProfile)), Effect.match({
|
|
2982
|
+
onSuccess: () => success("AWS: SSO logout complete"),
|
|
2983
|
+
onFailure: (e) => warn(`AWS: SSO logout failed: \`${e.message}\``)
|
|
2984
|
+
}))), Match.when({ method: "stored" }, () => store.delete(profileName, "aws").pipe(Effect.andThen(success("AWS: stored credentials removed")))), Match.exhaustive);
|
|
2985
|
+
const login = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, () => Effect.void), Match.when({ method: "sso" }, loginSSO), Match.when({ method: "stored" }, () => store.read(profileName, "aws").pipe(Effect.flatMap((creds) => creds == null ? loginStored(profileName) : Effect.void))), Match.exhaustive).pipe(Effect.mapError((e) => new AuthError({
|
|
2986
|
+
message: "login failed",
|
|
2987
|
+
cause: e
|
|
2988
|
+
})));
|
|
2989
|
+
return {
|
|
2990
|
+
configure: configureCredentials,
|
|
2991
|
+
login,
|
|
2992
|
+
logout,
|
|
2993
|
+
prettyPrint,
|
|
2994
|
+
read: resolveCredentials
|
|
2995
|
+
};
|
|
2996
|
+
}));
|
|
2997
|
+
const runSsoCommand = (command, ssoProfile) => Effect.gen(function* () {
|
|
2998
|
+
const exit = yield* (yield* ChildProcess.make("aws", [
|
|
2999
|
+
"sso",
|
|
3000
|
+
command,
|
|
3001
|
+
"--profile",
|
|
3002
|
+
ssoProfile
|
|
3003
|
+
], {
|
|
3004
|
+
shell: false,
|
|
3005
|
+
stdin: "inherit",
|
|
3006
|
+
stdout: "inherit",
|
|
3007
|
+
stderr: "inherit"
|
|
3008
|
+
})).exitCode;
|
|
3009
|
+
if (exit !== 0) return yield* new AuthError({ message: `aws sso ${command} exited with code ${exit}` });
|
|
3010
|
+
}).pipe(Effect.scoped);
|
|
3011
|
+
const loginSSO = (config) => info(`AWS SSO: running 'aws sso login --profile ${config.ssoProfile}'...`).pipe(Effect.andThen(runSsoCommand("login", config.ssoProfile)), Effect.matchEffect({
|
|
3012
|
+
onSuccess: () => success("AWS SSO: login complete"),
|
|
3013
|
+
onFailure: (e) => warn(`AWS SSO: login faield: \`${e.message}\``)
|
|
3014
|
+
}));
|
|
3015
|
+
/**
|
|
3016
|
+
* `aws sso logout` only clears AWS CLI's own caches — it does not know about the
|
|
3017
|
+
* `<sha1(sso_session)>.credentials.json` file that `@distilled.cloud/aws`
|
|
3018
|
+
* writes alongside the SSO token. Without this cleanup, `loadProfileCredentials`
|
|
3019
|
+
* short-circuits on the stale distilled cache file after logout and appears to
|
|
3020
|
+
* stay logged in until the role creds hit their TTL.
|
|
3021
|
+
*/
|
|
3022
|
+
const clearDistilledSsoCache = (ssoProfile) => Effect.gen(function* () {
|
|
3023
|
+
const ssoSession = (yield* (yield* DistilledAuth.Default).loadProfile(ssoProfile)).sso_session;
|
|
3024
|
+
if (!ssoSession) return;
|
|
3025
|
+
const fs$1 = yield* FileSystem.FileSystem;
|
|
3026
|
+
const path$2 = yield* Path$1.Path;
|
|
3027
|
+
const hash = NodeCrypto.createHash("sha1").update(ssoSession).digest("hex");
|
|
3028
|
+
const cacheFile = path$2.join(NodeOs.homedir(), ".aws", "sso", "cache", `${hash}.credentials.json`);
|
|
3029
|
+
yield* fs$1.remove(cacheFile).pipe(Effect.catch(() => Effect.void));
|
|
3030
|
+
}).pipe(Effect.catch(() => Effect.void));
|
|
3031
|
+
|
|
3032
|
+
//#endregion
|
|
3033
|
+
//#region lib/Axiom/AuthProvider.js
|
|
3034
|
+
init_AuthProvider();
|
|
3035
|
+
init_Credentials();
|
|
3036
|
+
const STORAGE_KEY = "axiom-stored";
|
|
3037
|
+
const options$4 = [{
|
|
3038
|
+
value: "env",
|
|
3039
|
+
label: "Environment Variables",
|
|
3040
|
+
hint: "AXIOM_TOKEN (or AXIOM_API_KEY) + optional AXIOM_ORG_ID, AXIOM_URL"
|
|
3041
|
+
}, {
|
|
3042
|
+
value: "stored",
|
|
3043
|
+
label: "API Token or Personal Access Token",
|
|
3044
|
+
hint: "enter credentials interactively, stored in ~/.alchemy/credentials"
|
|
3045
|
+
}];
|
|
3046
|
+
const AXIOM_AUTH_PROVIDER_NAME = "Axiom";
|
|
3047
|
+
const promptOrgId = (required) => getEnv("AXIOM_ORG_ID").pipe(Effect.flatMap((envOrgId) => text({
|
|
3048
|
+
message: required ? "Axiom Org ID (required for PAT)" : "Axiom Org ID (Enter to skip)",
|
|
3049
|
+
placeholder: envOrgId ?? "",
|
|
3050
|
+
defaultValue: envOrgId ?? "",
|
|
3051
|
+
validate: required ? (v) => v.length === 0 ? "Required" : void 0 : void 0
|
|
3052
|
+
}).pipe(retryOnce)));
|
|
3053
|
+
/**
|
|
3054
|
+
* Layer that registers the Axiom {@link AuthProvider} into the
|
|
3055
|
+
* {@link AuthProviders} registry when built. Include this in the Axiom
|
|
3056
|
+
* `providers()` layer so `alchemy login` can discover it.
|
|
3057
|
+
*/
|
|
3058
|
+
const AxiomAuth = AuthProviderLayer()(AXIOM_AUTH_PROVIDER_NAME, Effect.gen(function* () {
|
|
3059
|
+
const store = yield* CredentialsStore;
|
|
3060
|
+
const loginStored = Effect.fn(function* (profileName) {
|
|
3061
|
+
const credentialType = yield* select({
|
|
3062
|
+
message: "Axiom credential type",
|
|
3063
|
+
options: [{
|
|
3064
|
+
value: "apiToken",
|
|
3065
|
+
label: "API Token",
|
|
3066
|
+
hint: "recommended — scoped to specific datasets/actions"
|
|
3067
|
+
}, {
|
|
3068
|
+
value: "pat",
|
|
3069
|
+
label: "Personal Access Token",
|
|
3070
|
+
hint: "full account control, requires Org ID"
|
|
3071
|
+
}]
|
|
3072
|
+
}).pipe(retryOnce);
|
|
3073
|
+
const apiBaseUrlPrompt = yield* text({
|
|
3074
|
+
message: "Axiom API Base URL (Enter for default)",
|
|
3075
|
+
placeholder: DEFAULT_API_BASE_URL,
|
|
3076
|
+
defaultValue: DEFAULT_API_BASE_URL
|
|
3077
|
+
}).pipe(retryOnce);
|
|
3078
|
+
const apiBaseUrl = apiBaseUrlPrompt && apiBaseUrlPrompt.length > 0 ? apiBaseUrlPrompt : void 0;
|
|
3079
|
+
return yield* Match.value(credentialType).pipe(Match.when("apiToken", () => Effect.gen(function* () {
|
|
3080
|
+
const apiToken = yield* password({
|
|
3081
|
+
message: "Axiom API Token",
|
|
3082
|
+
validate: (v) => v.length === 0 ? "Required" : void 0
|
|
3083
|
+
}).pipe(retryOnce);
|
|
3084
|
+
const orgId = yield* promptOrgId(false);
|
|
3085
|
+
yield* store.write(profileName, STORAGE_KEY, {
|
|
3086
|
+
type: "apiToken",
|
|
3087
|
+
apiToken,
|
|
3088
|
+
apiBaseUrl,
|
|
3089
|
+
orgId: orgId && orgId.length > 0 ? orgId : void 0
|
|
3090
|
+
});
|
|
3091
|
+
yield* success("Axiom: credentials saved.");
|
|
3092
|
+
return {
|
|
3093
|
+
method: "stored",
|
|
3094
|
+
credentialType: "apiToken"
|
|
3095
|
+
};
|
|
3096
|
+
})), Match.when("pat", () => Effect.gen(function* () {
|
|
3097
|
+
const apiToken = yield* password({
|
|
3098
|
+
message: "Axiom Personal Access Token",
|
|
3099
|
+
validate: (v) => v.length === 0 ? "Required" : void 0
|
|
3100
|
+
}).pipe(retryOnce);
|
|
3101
|
+
const orgId = yield* promptOrgId(true);
|
|
3102
|
+
yield* store.write(profileName, STORAGE_KEY, {
|
|
3103
|
+
type: "pat",
|
|
3104
|
+
apiToken,
|
|
3105
|
+
apiBaseUrl,
|
|
3106
|
+
orgId
|
|
3107
|
+
});
|
|
3108
|
+
yield* success("Axiom: credentials saved.");
|
|
3109
|
+
return {
|
|
3110
|
+
method: "stored",
|
|
3111
|
+
credentialType: "pat"
|
|
3112
|
+
};
|
|
3113
|
+
})), Match.exhaustive);
|
|
3114
|
+
});
|
|
3115
|
+
const configureInteractive = (profileName) => select({
|
|
3116
|
+
message: "Axiom authentication method",
|
|
3117
|
+
options: options$4
|
|
3118
|
+
}).pipe(Effect.flatMap((method) => Match.value(method).pipe(Match.when("env", () => Effect.succeed({ method: "env" })), Match.when("stored", () => loginStored(profileName)), Match.exhaustive)));
|
|
3119
|
+
const configureCredentials = (profileName, ctx) => Effect.gen(function* () {
|
|
3120
|
+
if (ctx.ci) return { method: "env" };
|
|
3121
|
+
return yield* configureInteractive(profileName);
|
|
3122
|
+
}).pipe(Effect.mapError((e) => new AuthError({
|
|
3123
|
+
message: "failed to configure credentials",
|
|
3124
|
+
cause: e
|
|
3125
|
+
})));
|
|
3126
|
+
const resolveCredentials = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, Effect.fn(function* () {
|
|
3127
|
+
const apiToken = (yield* getEnvRedacted("AXIOM_TOKEN")) ?? (yield* getEnvRedacted("AXIOM_API_KEY"));
|
|
3128
|
+
if (!apiToken) return yield* new AuthError({ message: "Axiom env credentials not found. Set AXIOM_TOKEN (or AXIOM_API_KEY)." });
|
|
3129
|
+
const apiBaseUrl = (yield* getEnv("AXIOM_URL")) ?? DEFAULT_API_BASE_URL;
|
|
3130
|
+
const orgId = yield* getEnv("AXIOM_ORG_ID");
|
|
3131
|
+
if (orgId) return {
|
|
3132
|
+
type: "pat",
|
|
3133
|
+
apiToken,
|
|
3134
|
+
apiBaseUrl,
|
|
3135
|
+
orgId,
|
|
3136
|
+
source: { type: "env" }
|
|
3137
|
+
};
|
|
3138
|
+
return {
|
|
3139
|
+
type: "apiToken",
|
|
3140
|
+
apiToken,
|
|
3141
|
+
apiBaseUrl,
|
|
3142
|
+
source: { type: "env" }
|
|
3143
|
+
};
|
|
3144
|
+
})), Match.when({ method: "stored" }, () => store.read(profileName, STORAGE_KEY).pipe(Effect.flatMap((creds) => creds == null ? Effect.fail(new AuthError({ message: "Axiom stored credentials not found. Run: alchemy login --configure" })) : Effect.succeed(Match.value(creds).pipe(Match.when({ type: "apiToken" }, (c$1) => ({
|
|
3145
|
+
type: "apiToken",
|
|
3146
|
+
apiToken: Redacted.make(c$1.apiToken),
|
|
3147
|
+
apiBaseUrl: c$1.apiBaseUrl ?? DEFAULT_API_BASE_URL,
|
|
3148
|
+
orgId: c$1.orgId,
|
|
3149
|
+
source: { type: "stored" }
|
|
3150
|
+
})), Match.when({ type: "pat" }, (c$1) => ({
|
|
3151
|
+
type: "pat",
|
|
3152
|
+
apiToken: Redacted.make(c$1.apiToken),
|
|
3153
|
+
apiBaseUrl: c$1.apiBaseUrl ?? DEFAULT_API_BASE_URL,
|
|
3154
|
+
orgId: c$1.orgId,
|
|
3155
|
+
source: { type: "stored" }
|
|
3156
|
+
})), Match.exhaustive))))), Match.exhaustive);
|
|
3157
|
+
const logout = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, () => Effect.void), Match.when({ method: "stored" }, () => store.delete(profileName, STORAGE_KEY).pipe(Effect.andThen(success("Axiom: stored credentials removed")))), Match.exhaustive);
|
|
3158
|
+
const login = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, () => Effect.void), Match.when({ method: "stored" }, () => store.read(profileName, STORAGE_KEY).pipe(Effect.flatMap((creds) => creds == null ? loginStored(profileName) : Effect.void))), Match.exhaustive).pipe(Effect.mapError((e) => new AuthError({
|
|
3159
|
+
message: "login failed",
|
|
3160
|
+
cause: e
|
|
3161
|
+
})));
|
|
3162
|
+
const prettyPrint = (profileName, config) => resolveCredentials(profileName, config).pipe(Effect.tap((creds) => {
|
|
3163
|
+
const sourceStr = creds.source.details ? `${creds.source.type} - ${creds.source.details}` : creds.source.type;
|
|
3164
|
+
return Match.value(creds).pipe(Match.when({ type: "apiToken" }, (c$1) => Effect.all([
|
|
3165
|
+
Console.log(` apiToken: ${displayRedacted(c$1.apiToken, 9)}`),
|
|
3166
|
+
Console.log(` apiBaseUrl: ${c$1.apiBaseUrl}`),
|
|
3167
|
+
Console.log(` orgId: ${c$1.orgId ?? "(none)"}`),
|
|
3168
|
+
Console.log(` source: ${sourceStr}`)
|
|
3169
|
+
])), Match.when({ type: "pat" }, (c$1) => Effect.all([
|
|
3170
|
+
Console.log(` apiToken: ${displayRedacted(c$1.apiToken, 9)}`),
|
|
3171
|
+
Console.log(` apiBaseUrl: ${c$1.apiBaseUrl}`),
|
|
3172
|
+
Console.log(` orgId: ${c$1.orgId}`),
|
|
3173
|
+
Console.log(` source: ${sourceStr}`)
|
|
3174
|
+
])), Match.exhaustive);
|
|
3175
|
+
}));
|
|
3176
|
+
return {
|
|
3177
|
+
configure: configureCredentials,
|
|
3178
|
+
logout,
|
|
3179
|
+
login,
|
|
3180
|
+
prettyPrint,
|
|
3181
|
+
read: resolveCredentials
|
|
3182
|
+
};
|
|
3183
|
+
}));
|
|
3184
|
+
|
|
3185
|
+
//#endregion
|
|
3186
|
+
//#region lib/Cloudflare/StateStore/CredentialsFile.js
|
|
3187
|
+
/**
|
|
3188
|
+
* Filename (under `~/.alchemy/credentials/{profile}/`) used to cache the
|
|
3189
|
+
* Cloudflare-deployed HTTP state store's endpoint + bearer token.
|
|
3190
|
+
*
|
|
3191
|
+
* Kept in this leaf module (rather than `StateStore/State.ts`) so the
|
|
3192
|
+
* Cloudflare auth provider can invalidate the cache on
|
|
3193
|
+
* `login --configure` / `logout` without importing the heavy state-store
|
|
3194
|
+
* module and creating an import cycle
|
|
3195
|
+
* (`StateStore/State.ts` -> `Providers.ts` -> `Auth/AuthProvider.ts`).
|
|
3196
|
+
*/
|
|
3197
|
+
const CREDENTIALS_FILE = "cloudflare-state-store";
|
|
3198
|
+
|
|
3199
|
+
//#endregion
|
|
3200
|
+
//#region lib/Cloudflare/Auth/OAuthClient.js
|
|
3201
|
+
init_AuthProvider();
|
|
3202
|
+
var OAuthError$1 = class extends Data.TaggedError("OAuthError") {};
|
|
3203
|
+
function generateState$1(length = 32) {
|
|
3204
|
+
return crypto$1.randomBytes(length).toString("base64url");
|
|
3205
|
+
}
|
|
3206
|
+
function generatePKCE(length = 96) {
|
|
3207
|
+
const verifier = crypto$1.randomBytes(length).toString("base64url");
|
|
3208
|
+
return {
|
|
3209
|
+
verifier,
|
|
3210
|
+
challenge: crypto$1.createHash("sha256").update(verifier).digest("base64url")
|
|
3211
|
+
};
|
|
3212
|
+
}
|
|
3213
|
+
function extractCredentials$1(json) {
|
|
3214
|
+
return {
|
|
3215
|
+
type: "oauth",
|
|
3216
|
+
access: json.access_token,
|
|
3217
|
+
refresh: json.refresh_token,
|
|
3218
|
+
expires: Date.now() + json.expires_in * 1e3,
|
|
3219
|
+
scopes: json.scope.split(" ")
|
|
3220
|
+
};
|
|
3221
|
+
}
|
|
3222
|
+
const tokenRequest$1 = (body) => Effect.gen(function* () {
|
|
3223
|
+
const res = yield* Effect.tryPromise({
|
|
3224
|
+
try: () => fetch(OAUTH_ENDPOINTS$1.token, {
|
|
3225
|
+
method: "POST",
|
|
3226
|
+
headers: {
|
|
3227
|
+
Accept: "application/json",
|
|
3228
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
3229
|
+
},
|
|
3230
|
+
body: new URLSearchParams(body).toString()
|
|
3231
|
+
}),
|
|
3232
|
+
catch: (err) => new OAuthError$1({
|
|
3233
|
+
error: "network_error",
|
|
3234
|
+
errorDescription: `Token request failed: ${err}`
|
|
3235
|
+
})
|
|
3236
|
+
});
|
|
3237
|
+
if (!res.ok) {
|
|
3238
|
+
const json = yield* Effect.tryPromise({
|
|
3239
|
+
try: () => res.json(),
|
|
3240
|
+
catch: () => new OAuthError$1({
|
|
3241
|
+
error: "parse_error",
|
|
3242
|
+
errorDescription: `Token endpoint returned ${res.status}`
|
|
3243
|
+
})
|
|
3244
|
+
});
|
|
3245
|
+
return yield* new OAuthError$1({
|
|
3246
|
+
error: json.error,
|
|
3247
|
+
errorDescription: json.error_description
|
|
3248
|
+
});
|
|
3249
|
+
}
|
|
3250
|
+
return extractCredentials$1(yield* Effect.tryPromise({
|
|
3251
|
+
try: () => res.json(),
|
|
3252
|
+
catch: () => new OAuthError$1({
|
|
3253
|
+
error: "parse_error",
|
|
3254
|
+
errorDescription: "Failed to parse token response"
|
|
3255
|
+
})
|
|
3256
|
+
}));
|
|
3257
|
+
});
|
|
3258
|
+
/**
|
|
3259
|
+
* Generate an authorization URL with PKCE for the given scopes.
|
|
3260
|
+
*/
|
|
3261
|
+
function authorize$1(scopes) {
|
|
3262
|
+
const state = generateState$1();
|
|
3263
|
+
const pkce = generatePKCE();
|
|
3264
|
+
const url = new URL(OAUTH_ENDPOINTS$1.authorize);
|
|
3265
|
+
url.searchParams.set("client_id", OAUTH_CLIENT_ID$1);
|
|
3266
|
+
url.searchParams.set("redirect_uri", OAUTH_REDIRECT_URI$1);
|
|
3267
|
+
url.searchParams.set("response_type", "code");
|
|
3268
|
+
url.searchParams.set("scope", scopes.join(" "));
|
|
3269
|
+
url.searchParams.set("state", state);
|
|
3270
|
+
url.searchParams.set("code_challenge", pkce.challenge);
|
|
3271
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
3272
|
+
return {
|
|
3273
|
+
url: url.toString(),
|
|
3274
|
+
state,
|
|
3275
|
+
verifier: pkce.verifier
|
|
3276
|
+
};
|
|
3277
|
+
}
|
|
3278
|
+
/**
|
|
3279
|
+
* Exchange an authorization code for OAuth credentials.
|
|
3280
|
+
*/
|
|
3281
|
+
const exchange$1 = (code, verifier) => tokenRequest$1({
|
|
3282
|
+
grant_type: "authorization_code",
|
|
3283
|
+
code,
|
|
3284
|
+
code_verifier: verifier,
|
|
3285
|
+
client_id: OAUTH_CLIENT_ID$1,
|
|
3286
|
+
redirect_uri: OAUTH_REDIRECT_URI$1
|
|
3287
|
+
});
|
|
3288
|
+
/**
|
|
3289
|
+
* Refresh expired OAuth credentials.
|
|
3290
|
+
*/
|
|
3291
|
+
const refresh$1 = (credentials) => tokenRequest$1({
|
|
3292
|
+
grant_type: "refresh_token",
|
|
3293
|
+
refresh_token: credentials.refresh,
|
|
3294
|
+
client_id: OAUTH_CLIENT_ID$1,
|
|
3295
|
+
redirect_uri: OAUTH_REDIRECT_URI$1
|
|
3296
|
+
});
|
|
3297
|
+
/**
|
|
3298
|
+
* Revoke OAuth credentials.
|
|
3299
|
+
*/
|
|
3300
|
+
const revoke = (credentials) => Effect.gen(function* () {
|
|
3301
|
+
yield* Effect.tryPromise({
|
|
3302
|
+
try: () => fetch(OAUTH_ENDPOINTS$1.revoke, {
|
|
3303
|
+
method: "POST",
|
|
3304
|
+
headers: {
|
|
3305
|
+
Accept: "application/json",
|
|
3306
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
3307
|
+
},
|
|
3308
|
+
body: new URLSearchParams({
|
|
3309
|
+
refresh_token: credentials.refresh,
|
|
3310
|
+
client_id: OAUTH_CLIENT_ID$1,
|
|
3311
|
+
redirect_uri: OAUTH_REDIRECT_URI$1
|
|
3312
|
+
}).toString()
|
|
3313
|
+
}),
|
|
3314
|
+
catch: (err) => new OAuthError$1({
|
|
3315
|
+
error: "network_error",
|
|
3316
|
+
errorDescription: `Revoke request failed: ${err}`
|
|
3317
|
+
})
|
|
3318
|
+
});
|
|
3319
|
+
});
|
|
3320
|
+
/**
|
|
3321
|
+
* Start a local HTTP server to listen for the OAuth callback, exchange
|
|
3322
|
+
* the authorization code, and return the credentials.
|
|
3323
|
+
*
|
|
3324
|
+
* Times out after 5 minutes.
|
|
3325
|
+
*/
|
|
3326
|
+
const callback$1 = (authorization) => Effect.tryPromise({
|
|
3327
|
+
try: () => callbackPromise$1(authorization),
|
|
3328
|
+
catch: (err) => {
|
|
3329
|
+
if (err instanceof OAuthError$1) return err;
|
|
3330
|
+
return new OAuthError$1({
|
|
3331
|
+
error: "callback_error",
|
|
3332
|
+
errorDescription: `OAuth callback failed: ${err}`
|
|
3333
|
+
});
|
|
3334
|
+
}
|
|
3335
|
+
});
|
|
3336
|
+
function callbackPromise$1(authorization) {
|
|
3337
|
+
const { pathname, port } = new URL(OAUTH_REDIRECT_URI$1);
|
|
3338
|
+
return new Promise((resolve, reject) => {
|
|
3339
|
+
const server = http.createServer(async (req, res) => {
|
|
3340
|
+
const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
|
|
3341
|
+
if (url.pathname !== pathname) {
|
|
3342
|
+
res.statusCode = 404;
|
|
3343
|
+
res.end("Not Found");
|
|
3344
|
+
return;
|
|
3345
|
+
}
|
|
3346
|
+
const error = url.searchParams.get("error");
|
|
3347
|
+
const errorDescription = url.searchParams.get("error_description");
|
|
3348
|
+
if (error) {
|
|
3349
|
+
res.writeHead(302, { Location: AUTH_ERROR_URL });
|
|
3350
|
+
res.end();
|
|
3351
|
+
cleanup();
|
|
3352
|
+
reject(new OAuthError$1({
|
|
3353
|
+
error,
|
|
3354
|
+
errorDescription: errorDescription ?? "An unknown error occurred."
|
|
3355
|
+
}));
|
|
3356
|
+
return;
|
|
3357
|
+
}
|
|
3358
|
+
const code = url.searchParams.get("code");
|
|
3359
|
+
const state = url.searchParams.get("state");
|
|
3360
|
+
if (!code || !state) {
|
|
3361
|
+
res.writeHead(302, { Location: AUTH_ERROR_URL });
|
|
3362
|
+
res.end();
|
|
3363
|
+
cleanup();
|
|
3364
|
+
reject(new OAuthError$1({
|
|
3365
|
+
error: "invalid_request",
|
|
3366
|
+
errorDescription: "Missing code or state"
|
|
3367
|
+
}));
|
|
3368
|
+
return;
|
|
3369
|
+
}
|
|
3370
|
+
if (state !== authorization.state) {
|
|
3371
|
+
res.writeHead(302, { Location: AUTH_ERROR_URL });
|
|
3372
|
+
res.end();
|
|
3373
|
+
cleanup();
|
|
3374
|
+
reject(new OAuthError$1({
|
|
3375
|
+
error: "invalid_request",
|
|
3376
|
+
errorDescription: "Invalid state"
|
|
3377
|
+
}));
|
|
3378
|
+
return;
|
|
3379
|
+
}
|
|
3380
|
+
try {
|
|
3381
|
+
const credentials = await Effect.runPromise(exchange$1(code, authorization.verifier));
|
|
3382
|
+
res.writeHead(302, { Location: AUTH_SUCCESS_URL });
|
|
3383
|
+
res.end();
|
|
3384
|
+
cleanup();
|
|
3385
|
+
resolve(credentials);
|
|
3386
|
+
} catch (err) {
|
|
3387
|
+
res.writeHead(302, { Location: AUTH_ERROR_URL });
|
|
3388
|
+
res.end();
|
|
3389
|
+
cleanup();
|
|
3390
|
+
reject(err);
|
|
3391
|
+
}
|
|
3392
|
+
});
|
|
3393
|
+
const timeout = setTimeout(() => {
|
|
3394
|
+
cleanup();
|
|
3395
|
+
reject(new OAuthError$1({
|
|
3396
|
+
error: "timeout",
|
|
3397
|
+
errorDescription: "The authorization process timed out."
|
|
3398
|
+
}));
|
|
3399
|
+
}, 300 * 1e3);
|
|
3400
|
+
function cleanup() {
|
|
3401
|
+
clearTimeout(timeout);
|
|
3402
|
+
server.close();
|
|
3403
|
+
}
|
|
3404
|
+
server.on("error", (err) => {
|
|
3405
|
+
cleanup();
|
|
3406
|
+
reject(new OAuthError$1({
|
|
3407
|
+
error: "server_error",
|
|
3408
|
+
errorDescription: `Failed to start callback server: ${err.message}`
|
|
3409
|
+
}));
|
|
3410
|
+
});
|
|
3411
|
+
server.listen(Number(port));
|
|
3412
|
+
});
|
|
3413
|
+
}
|
|
3414
|
+
|
|
3415
|
+
//#endregion
|
|
3416
|
+
//#region lib/Cloudflare/Auth/AuthProvider.js
|
|
3417
|
+
init_AuthProvider();
|
|
3418
|
+
init_Credentials();
|
|
3419
|
+
const options$3 = [
|
|
3420
|
+
{
|
|
3421
|
+
value: "oauth",
|
|
3422
|
+
label: "OAuth",
|
|
3423
|
+
hint: "recommended — browser-based login with automatic token refresh"
|
|
3424
|
+
},
|
|
3425
|
+
{
|
|
3426
|
+
value: "env",
|
|
3427
|
+
label: "Environment Variables",
|
|
3428
|
+
hint: "CLOUDFLARE_API_TOKEN or CLOUDFLARE_API_KEY + CLOUDFLARE_EMAIL"
|
|
3429
|
+
},
|
|
3430
|
+
{
|
|
3431
|
+
value: "stored",
|
|
3432
|
+
label: "API Token or API Key",
|
|
3433
|
+
hint: "enter credentials interactively, stored in ~/.alchemy/credentials"
|
|
3434
|
+
}
|
|
3435
|
+
];
|
|
3436
|
+
const CLOUDFLARE_AUTH_PROVIDER_NAME = "Cloudflare";
|
|
3437
|
+
const withOAuthCredentials$1 = (accessToken, effect) => Effect.provide(effect, Layer.mergeAll(CfCredentialsModule.fromOAuth({
|
|
3438
|
+
load: Effect.succeed({ accessToken }),
|
|
3439
|
+
refresh: () => Effect.die("refresh not expected during account selection")
|
|
3440
|
+
}), FetchHttpClient.layer));
|
|
3441
|
+
const selectAccount = (accessToken) => Effect.gen(function* () {
|
|
3442
|
+
const accounts = (yield* (yield* cfAccounts.listAccounts)({})).result;
|
|
3443
|
+
if (accounts.length === 0) return yield* new AuthError({ message: "Cloudflare: no accounts found for this credential." });
|
|
3444
|
+
if (accounts.length === 1) {
|
|
3445
|
+
const account = accounts[0];
|
|
3446
|
+
yield* info(`Cloudflare: using account: ${account.name} (${account.id})`);
|
|
3447
|
+
return account.id;
|
|
3448
|
+
}
|
|
3449
|
+
return yield* select({
|
|
3450
|
+
message: "Select a Cloudflare account",
|
|
3451
|
+
options: accounts.map((a) => ({
|
|
3452
|
+
value: a.id,
|
|
3453
|
+
label: a.name,
|
|
3454
|
+
hint: a.id
|
|
3455
|
+
}))
|
|
3456
|
+
}).pipe(retryOnce);
|
|
3457
|
+
}).pipe((e) => withOAuthCredentials$1(accessToken, e));
|
|
3458
|
+
/**
|
|
3459
|
+
* Cloudflare account IDs are 32 lowercase hex characters. Placeholder
|
|
3460
|
+
* values ("", "-", "dummy", …) end up interpolated into API paths and
|
|
3461
|
+
* surface as baffling `InvalidRoute: Could not route to
|
|
3462
|
+
* /accounts/<value>/...` errors, so reject them up front with an
|
|
3463
|
+
* actionable message instead.
|
|
3464
|
+
*/
|
|
3465
|
+
const ACCOUNT_ID_PATTERN = /^[0-9a-f]{32}$/i;
|
|
3466
|
+
const validateAccountId = (accountId, source) => {
|
|
3467
|
+
const trimmed = accountId?.trim() ?? "";
|
|
3468
|
+
if (trimmed.length === 0) return Effect.fail(new AuthError({ message: `Cloudflare account ID is missing (${source}). Set CLOUDFLARE_ACCOUNT_ID or re-run 'alchemy login' and provide your account ID (found in the Cloudflare dashboard under Workers & Pages → Account details).` }));
|
|
3469
|
+
if (!ACCOUNT_ID_PATTERN.test(trimmed)) return Effect.fail(new AuthError({ message: `'${trimmed}' is not a valid Cloudflare account ID (${source}) — expected 32 hex characters. Copy the account ID from the Cloudflare dashboard (Workers & Pages → Account details) into CLOUDFLARE_ACCOUNT_ID or re-run 'alchemy login'.` }));
|
|
3470
|
+
return Effect.succeed(trimmed.toLowerCase());
|
|
3471
|
+
};
|
|
3472
|
+
const promptAccountId = () => getEnv("CLOUDFLARE_ACCOUNT_ID").pipe(Effect.flatMap((envAccountId) => text({
|
|
3473
|
+
message: "Cloudflare Account ID (Enter to skip)",
|
|
3474
|
+
placeholder: envAccountId ?? "",
|
|
3475
|
+
defaultValue: envAccountId ?? "",
|
|
3476
|
+
validate: (v) => v.trim().length === 0 || ACCOUNT_ID_PATTERN.test(v.trim()) ? void 0 : "Expected a 32-character hex account ID (Workers & Pages → Account details)"
|
|
3477
|
+
}).pipe(retryOnce)));
|
|
3478
|
+
const promptOAuthScopes = () => confirm({
|
|
3479
|
+
message: "Customize OAuth scopes? (default covers typical use cases)",
|
|
3480
|
+
initialValue: false
|
|
3481
|
+
}).pipe(retryOnce, Effect.flatMap((customize) => {
|
|
3482
|
+
if (!customize) return Effect.succeed([...DEFAULT_SCOPES]);
|
|
3483
|
+
return multiselect({
|
|
3484
|
+
message: "Select OAuth scopes",
|
|
3485
|
+
initialValues: DEFAULT_SCOPES,
|
|
3486
|
+
options: Object.entries(ALL_SCOPES).map(([value, hint]) => ({
|
|
3487
|
+
value,
|
|
3488
|
+
label: value,
|
|
3489
|
+
hint
|
|
3490
|
+
})),
|
|
3491
|
+
required: true
|
|
3492
|
+
}).pipe(Effect.map((s) => s), retryOnce);
|
|
3493
|
+
}));
|
|
3494
|
+
/**
|
|
3495
|
+
* Layer that registers the Cloudflare {@link AuthProvider} into the
|
|
3496
|
+
* {@link AuthProviders} registry when built. Include this in the Cloudflare
|
|
3497
|
+
* `providers()` layer so `alchemy login` can discover it.
|
|
3498
|
+
*/
|
|
3499
|
+
const CloudflareAuth = AuthProviderLayer()(CLOUDFLARE_AUTH_PROVIDER_NAME, Effect.gen(function* () {
|
|
3500
|
+
const store = yield* CredentialsStore;
|
|
3501
|
+
const oauthLogin = (profileName, scopes) => Effect.gen(function* () {
|
|
3502
|
+
const authorization = authorize$1([...scopes, "offline_access"]);
|
|
3503
|
+
yield* info("Cloudflare: opening browser for OAuth login...");
|
|
3504
|
+
yield* info(authorization.url);
|
|
3505
|
+
yield* openUrl(authorization.url).pipe(Effect.catch(() => warn("Cloudflare: could not open browser automatically. Please open the URL above manually.")));
|
|
3506
|
+
yield* info("Cloudflare: waiting for authorization (up to 5 minutes)...");
|
|
3507
|
+
const credentials = yield* callback$1(authorization);
|
|
3508
|
+
yield* store.write(profileName, "cf-oauth", credentials);
|
|
3509
|
+
yield* success("Cloudflare: OAuth credentials saved.");
|
|
3510
|
+
return credentials;
|
|
3511
|
+
});
|
|
3512
|
+
const loginStored = Effect.fn(function* (profileName) {
|
|
3513
|
+
const credentialType = yield* select({
|
|
3514
|
+
message: "Cloudflare credential type",
|
|
3515
|
+
options: [{
|
|
3516
|
+
value: "apiToken",
|
|
3517
|
+
label: "API Token",
|
|
3518
|
+
hint: "recommended"
|
|
3519
|
+
}, {
|
|
3520
|
+
value: "apiKey",
|
|
3521
|
+
label: "API Key + Email"
|
|
3522
|
+
}]
|
|
3523
|
+
}).pipe(retryOnce);
|
|
3524
|
+
return yield* Match.value(credentialType).pipe(Match.when("apiToken", () => Effect.gen(function* () {
|
|
3525
|
+
const apiToken = yield* password({
|
|
3526
|
+
message: "Cloudflare API Token",
|
|
3527
|
+
validate: (v) => v.length === 0 ? "Required" : void 0
|
|
3528
|
+
}).pipe(retryOnce);
|
|
3529
|
+
const accountId = yield* promptAccountId();
|
|
3530
|
+
yield* store.write(profileName, "cf-stored", {
|
|
3531
|
+
type: "apiToken",
|
|
3532
|
+
apiToken,
|
|
3533
|
+
accountId
|
|
3534
|
+
});
|
|
3535
|
+
yield* success("Cloudflare: credentials saved.");
|
|
3536
|
+
return {
|
|
3537
|
+
method: "stored",
|
|
3538
|
+
credentialType: "apiToken"
|
|
3539
|
+
};
|
|
3540
|
+
})), Match.when("apiKey", () => Effect.gen(function* () {
|
|
3541
|
+
const apiKey = yield* text({
|
|
3542
|
+
message: "Cloudflare API Key",
|
|
3543
|
+
validate: (v) => v.length === 0 ? "Required" : void 0
|
|
3544
|
+
}).pipe(retryOnce);
|
|
3545
|
+
const email = yield* text({
|
|
3546
|
+
message: "Cloudflare Email",
|
|
3547
|
+
validate: (v) => v.length === 0 ? "Required" : void 0
|
|
3548
|
+
}).pipe(retryOnce);
|
|
3549
|
+
const accountId = yield* promptAccountId();
|
|
3550
|
+
yield* store.write(profileName, "cf-stored", {
|
|
3551
|
+
type: "apiKey",
|
|
3552
|
+
apiKey,
|
|
3553
|
+
email,
|
|
3554
|
+
accountId
|
|
3555
|
+
});
|
|
3556
|
+
yield* success("Cloudflare: credentials saved.");
|
|
3557
|
+
return {
|
|
3558
|
+
method: "stored",
|
|
3559
|
+
credentialType: "apiKey"
|
|
3560
|
+
};
|
|
3561
|
+
})), Match.exhaustive);
|
|
3562
|
+
});
|
|
3563
|
+
const configureOAuth = Effect.fn(function* (profileName) {
|
|
3564
|
+
const scopes = yield* promptOAuthScopes();
|
|
3565
|
+
return {
|
|
3566
|
+
method: "oauth",
|
|
3567
|
+
scopes,
|
|
3568
|
+
accountId: yield* selectAccount((yield* oauthLogin(profileName, scopes)).access).pipe(Effect.mapError((e) => new AuthError({
|
|
3569
|
+
message: "Cloudflare: could not list accounts",
|
|
3570
|
+
cause: e
|
|
3571
|
+
})))
|
|
3572
|
+
};
|
|
3573
|
+
});
|
|
3574
|
+
const configureInteractive = (profileName) => select({
|
|
3575
|
+
message: "Cloudflare authentication method",
|
|
3576
|
+
options: options$3
|
|
3577
|
+
}).pipe(Effect.flatMap((method) => Match.value(method).pipe(Match.when("env", () => Effect.succeed({ method: "env" })), Match.when("oauth", () => configureOAuth(profileName)), Match.when("stored", () => loginStored(profileName)), Match.exhaustive)));
|
|
3578
|
+
const configureCredentials = (profileName, ctx) => Effect.gen(function* () {
|
|
3579
|
+
const config = ctx.ci ? { method: "env" } : yield* configureInteractive(profileName);
|
|
3580
|
+
yield* store.delete(profileName, CREDENTIALS_FILE).pipe(Effect.ignore);
|
|
3581
|
+
return config;
|
|
3582
|
+
}).pipe(Effect.mapError((e) => new AuthError({
|
|
3583
|
+
message: "failed to configure credentials",
|
|
3584
|
+
cause: e
|
|
3585
|
+
})));
|
|
3586
|
+
const resolveCredentials = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, Effect.fn(function* () {
|
|
3587
|
+
const accountId = yield* getEnvRequired("CLOUDFLARE_ACCOUNT_ID").pipe(Effect.flatMap((id) => validateAccountId(id, "from the CLOUDFLARE_ACCOUNT_ID env var")));
|
|
3588
|
+
const apiToken = yield* getEnvRedacted("CLOUDFLARE_API_TOKEN");
|
|
3589
|
+
if (apiToken) return {
|
|
3590
|
+
type: "apiToken",
|
|
3591
|
+
apiToken,
|
|
3592
|
+
accountId,
|
|
3593
|
+
source: { type: "env" }
|
|
3594
|
+
};
|
|
3595
|
+
const apiKey = yield* getEnvRedacted("CLOUDFLARE_API_KEY");
|
|
3596
|
+
const email = yield* getEnvRedacted("CLOUDFLARE_EMAIL");
|
|
3597
|
+
if (apiKey && email) return {
|
|
3598
|
+
type: "apiKey",
|
|
3599
|
+
apiKey,
|
|
3600
|
+
email,
|
|
3601
|
+
accountId,
|
|
3602
|
+
source: { type: "env" }
|
|
3603
|
+
};
|
|
3604
|
+
return yield* new AuthError({ message: "Cloudflare env credentials not found. Set CLOUDFLARE_API_TOKEN or CLOUDFLARE_API_KEY + CLOUDFLARE_EMAIL." });
|
|
3605
|
+
})), Match.when({ method: "stored" }, () => store.read(profileName, "cf-stored").pipe(Effect.flatMap((creds) => creds == null ? Effect.fail(new AuthError({ message: "Cloudflare stored credentials not found. Run: alchemy login --configure" })) : Effect.gen(function* () {
|
|
3606
|
+
const envAccountId = yield* getEnv("CLOUDFLARE_ACCOUNT_ID");
|
|
3607
|
+
const accountId = yield* validateAccountId(creds.accountId?.trim() || envAccountId, `stored for profile '${profileName}'`);
|
|
3608
|
+
return Match.value(creds).pipe(Match.when({ type: "apiToken" }, (c$1) => ({
|
|
3609
|
+
type: "apiToken",
|
|
3610
|
+
apiToken: Redacted.make(c$1.apiToken),
|
|
3611
|
+
accountId,
|
|
3612
|
+
source: { type: "stored" }
|
|
3613
|
+
})), Match.when({ type: "apiKey" }, (c$1) => ({
|
|
3614
|
+
type: "apiKey",
|
|
3615
|
+
apiKey: Redacted.make(c$1.apiKey),
|
|
3616
|
+
email: Redacted.make(c$1.email),
|
|
3617
|
+
accountId,
|
|
3618
|
+
source: { type: "stored" }
|
|
3619
|
+
})), Match.exhaustive);
|
|
3620
|
+
})))), Match.when({ method: "oauth" }, (cfg) => Effect.gen(function* () {
|
|
3621
|
+
const accountId = yield* validateAccountId(cfg.accountId, `configured for profile '${profileName}'`);
|
|
3622
|
+
const creds = yield* store.read(profileName, "cf-oauth");
|
|
3623
|
+
if (creds == null || creds.type !== "oauth") return yield* Effect.fail(new AuthError({ message: "Cloudflare OAuth credentials not found. Run: alchemy login" }));
|
|
3624
|
+
const fresh = creds.expires > Date.now() + 1e4 ? creds : yield* refresh$1(creds).pipe(Effect.tap((refreshed) => store.write(profileName, "cf-oauth", refreshed)), Effect.mapError((e) => new AuthError({
|
|
3625
|
+
message: "Cloudflare OAuth refresh failed. Run: alchemy login",
|
|
3626
|
+
cause: e
|
|
3627
|
+
})));
|
|
3628
|
+
return {
|
|
3629
|
+
type: "oauth",
|
|
3630
|
+
accessToken: Redacted.make(fresh.access),
|
|
3631
|
+
expires: fresh.expires,
|
|
3632
|
+
accountId,
|
|
3633
|
+
source: { type: "oauth" }
|
|
3634
|
+
};
|
|
3635
|
+
})), Match.exhaustive);
|
|
3636
|
+
const logout = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, () => Effect.void), Match.when({ method: "stored" }, () => store.delete(profileName, "cf-stored").pipe(Effect.andThen(success("Cloudflare: stored credentials removed")))), Match.when({ method: "oauth" }, () => store.read(profileName, "cf-oauth").pipe(Effect.tap((creds) => creds?.type === "oauth" ? revoke(creds).pipe(Effect.catchTag("OAuthError", (err) => warn(`Cloudflare: could not revoke OAuth token: ${err.errorDescription}`))) : Effect.void), Effect.andThen(store.delete(profileName, "cf-oauth")), Effect.andThen(success("Cloudflare: OAuth credentials removed.")))), Match.exhaustive).pipe(Effect.andThen(store.delete(profileName, CREDENTIALS_FILE).pipe(Effect.ignore)));
|
|
3637
|
+
const login = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, () => Effect.void), Match.when({ method: "stored" }, () => store.read(profileName, "cf-stored").pipe(Effect.flatMap((creds) => creds == null ? loginStored(profileName) : Effect.void))), Match.when({ method: "oauth" }, (c$1) => Effect.gen(function* () {
|
|
3638
|
+
const creds = yield* store.read(profileName, "cf-oauth");
|
|
3639
|
+
if (creds?.type === "oauth") {
|
|
3640
|
+
yield* info("Cloudflare: refreshing OAuth credentials...");
|
|
3641
|
+
yield* refresh$1(creds).pipe(Effect.flatMap((refreshed) => store.write(profileName, "cf-oauth", refreshed).pipe(Effect.andThen(success("Cloudflare: OAuth credentials refreshed.")))), Effect.catchTag("OAuthError", () => oauthLogin(profileName, c$1.scopes).pipe(Effect.asVoid)));
|
|
3642
|
+
return;
|
|
3643
|
+
}
|
|
3644
|
+
yield* oauthLogin(profileName, c$1.scopes);
|
|
3645
|
+
})), Match.exhaustive).pipe(Effect.mapError((e) => new AuthError({
|
|
3646
|
+
message: "login failed",
|
|
3647
|
+
cause: e
|
|
3648
|
+
})));
|
|
3649
|
+
const prettyPrint = (profileName, config) => resolveCredentials(profileName, config).pipe(Effect.tap((creds) => {
|
|
3650
|
+
const sourceStr = creds.source.details ? `${creds.source.type} - ${creds.source.details}` : creds.source.type;
|
|
3651
|
+
return Match.value(creds).pipe(Match.when({ type: "apiToken" }, (c$1) => Effect.all([
|
|
3652
|
+
Console.log(` apiToken: ${displayRedacted(c$1.apiToken, 9)}`),
|
|
3653
|
+
Console.log(` accountId: ${c$1.accountId}`),
|
|
3654
|
+
Console.log(` source: ${sourceStr}`)
|
|
3655
|
+
])), Match.when({ type: "apiKey" }, (c$1) => Effect.all([
|
|
3656
|
+
Console.log(` apiKey: ${displayRedacted(c$1.apiKey)}`),
|
|
3657
|
+
Console.log(` email: ${displayRedacted(c$1.email)}`),
|
|
3658
|
+
Console.log(` accountId: ${c$1.accountId}`),
|
|
3659
|
+
Console.log(` source: ${sourceStr}`)
|
|
3660
|
+
])), Match.when({ type: "oauth" }, (c$1) => {
|
|
3661
|
+
const remainingMs = c$1.expires - Date.now();
|
|
3662
|
+
const expiresAt = new Date(c$1.expires).toISOString();
|
|
3663
|
+
const expiresStr = remainingMs <= 0 ? `expired (${expiresAt})` : `in ${Duration.format(Duration.millis(remainingMs))} (${expiresAt})`;
|
|
3664
|
+
return Effect.all([
|
|
3665
|
+
Console.log(` accessToken: ${displayRedacted(c$1.accessToken)}`),
|
|
3666
|
+
Console.log(` expires: ${expiresStr}`),
|
|
3667
|
+
Console.log(` accountId: ${c$1.accountId}`),
|
|
3668
|
+
Console.log(` source: ${sourceStr}`)
|
|
3669
|
+
]);
|
|
3670
|
+
}), Match.exhaustive);
|
|
3671
|
+
}));
|
|
3672
|
+
return {
|
|
3673
|
+
configure: configureCredentials,
|
|
3674
|
+
logout,
|
|
3675
|
+
login,
|
|
3676
|
+
prettyPrint,
|
|
3677
|
+
read: resolveCredentials
|
|
3678
|
+
};
|
|
3679
|
+
}));
|
|
3680
|
+
const ALL_SCOPES = {
|
|
3681
|
+
"access:read": "See Cloudflare Access data such as zones, applications, certificates, device postures, groups, identity providers, login counts, organizations, policies, service tokens, and users",
|
|
3682
|
+
"access:write": "See and change Cloudflare Access data such as zones, applications, certificates, device postures, groups, identity providers, login counts, organizations, policies, service tokens, and users",
|
|
3683
|
+
"account:read": "See your account info such as account details, analytics, and memberships",
|
|
3684
|
+
"agw:read": "Grants read level access to Agents Gateway",
|
|
3685
|
+
"agw:run": "Grants run level access to Agents Gateway",
|
|
3686
|
+
"agw:write": "Grants read and write level access to Agents Gateway",
|
|
3687
|
+
"ai:read": "Grants read level access to Workers AI",
|
|
3688
|
+
"ai:write": "Grants write level access to Workers AI",
|
|
3689
|
+
"aiaudit:read": "Grants read level access to AI Audit",
|
|
3690
|
+
"aiaudit:write": "Grants write level access to AI Audit",
|
|
3691
|
+
"aig:read": "Grants read level access to AI Gateway",
|
|
3692
|
+
"aig:write": "Grants write level access to AI Gateway",
|
|
3693
|
+
"auditlogs:read": "View Cloudflare Account Audit Logs",
|
|
3694
|
+
"browser:read": "Grants read level access to Browser Rendering",
|
|
3695
|
+
"browser:write": "Grants write level access to Browser Rendering",
|
|
3696
|
+
"cfone:read": "Grants read level access to Cloudforce One data",
|
|
3697
|
+
"cfone:write": "Grants write level access to Cloudforce One data",
|
|
3698
|
+
"cloudchamber:write": "See and make changes to Cloudchamber",
|
|
3699
|
+
"connectivity:admin": "See, change, and bind to Connectivity Directory services, including creating services targeting Cloudflare Tunnel",
|
|
3700
|
+
"connectivity:bind": "read, list, and bind to Connectivity Directory services, as well as read and list Cloudflare Tunnels",
|
|
3701
|
+
"connectivity:read": "See Connectivity Directory services and Cloudflare Tunnels",
|
|
3702
|
+
"constellation:write": "Grants write access to Constellation configuration and models",
|
|
3703
|
+
"containers:write": "See and make changes to Workers Containers",
|
|
3704
|
+
"d1:write": "See and make changes to D1",
|
|
3705
|
+
"dex:read": "Grants read level access to Cloudflare DEX",
|
|
3706
|
+
"dex:write": "Grants write level access to Cloudflare DEX",
|
|
3707
|
+
"dns_analytics:read": "Grants read level access to Cloudflare DNS Analytics",
|
|
3708
|
+
"dns_records:edit": "Grants edit level access to dns records",
|
|
3709
|
+
"dns_records:read": "Grants read level access to dns records",
|
|
3710
|
+
"dns_settings:read": "Grants read level access to Cloudflare DNS Settings",
|
|
3711
|
+
"firstpartytags:write": "Can see, edit and publish Google tag gateway configuration.",
|
|
3712
|
+
"lb:edit": "Grants edit level access to lb and lb pools",
|
|
3713
|
+
"lb:read": "Grants read level access to lb and lb pools",
|
|
3714
|
+
"logpush:read": "See Cloudflare Logpush data",
|
|
3715
|
+
"logpush:write": "See and change Cloudflare Logpush data",
|
|
3716
|
+
"notification:read": "View Cloudflare Notifications",
|
|
3717
|
+
"notification:write": "View and Modify Cloudflare Notifications",
|
|
3718
|
+
"pages:read": "See Cloudflare Pages projects, settings and deployments",
|
|
3719
|
+
"pages:write": "See and change Cloudflare Pages projects, settings and deployments",
|
|
3720
|
+
"pipelines:read": "Grants read level access to Cloudflare Pipelines",
|
|
3721
|
+
"pipelines:setup": "Grants permission to generate R2 tokens for Workers Pipelines",
|
|
3722
|
+
"pipelines:write": "Grants write level access to Cloudflare Pipelines",
|
|
3723
|
+
"query_cache:write": "See and make changes to Hyperdrive",
|
|
3724
|
+
"queues:write": "See and change Cloudflare Queues settings and data",
|
|
3725
|
+
"r2_catalog:write": "Grants write level access to R2 Data Catalog",
|
|
3726
|
+
"radar:read": "Grants access to read Cloudflare Radar data",
|
|
3727
|
+
"ai-search:read": "Grants read level access to AI Search",
|
|
3728
|
+
"ai-search:write": "Grants write level access to AI Search",
|
|
3729
|
+
"ai-search:run": "Grants run level access to AI Search",
|
|
3730
|
+
"secrets_store:read": "Grants read level access to Secrets Store",
|
|
3731
|
+
"secrets_store:write": "Grants write level access to Secrets Store",
|
|
3732
|
+
"ssl_certs:write": "Grants read and write access to SSL MTLS certificates or Certificate Store",
|
|
3733
|
+
"sso-connector:read": "See Cloudflare SSO connectors",
|
|
3734
|
+
"sso-connector:write": "See Cloudflare SSO connectors to toggle activation and deactivation of SSO",
|
|
3735
|
+
"teams:pii": "See personally identifiable Cloudflare Teams data",
|
|
3736
|
+
"teams:read": "See Cloudflare Teams data such as zones, gateway, and argo tunnel details",
|
|
3737
|
+
"teams:secure_location": "See all DNS Location data but can only change secure DNS Locations",
|
|
3738
|
+
"teams:write": "See and change Cloudflare Teams data such as zones, gateway, and argo tunnel details",
|
|
3739
|
+
"url_scanner:read": "Grants read level access to URL Scanner",
|
|
3740
|
+
"url_scanner:write": "Grants write level access to URL Scanner",
|
|
3741
|
+
"user:read": "See your user info such as name, email address, and account memberships",
|
|
3742
|
+
"vectorize:write": "See and make changes to Vectorize",
|
|
3743
|
+
"workers:read": "See Cloudflare Workers data such as zones, KV storage, R2 storage, scripts, and routes",
|
|
3744
|
+
"workers:write": "See and change Cloudflare Workers data such as zones, KV storage, R2 storage, scripts, and routes",
|
|
3745
|
+
"workers_builds:read": "See Cloudflare Workers Builds data such as builds, build configuration, and build logs",
|
|
3746
|
+
"workers_builds:write": "See and change Cloudflare Workers Builds data such as builds, build configuration, and build logs",
|
|
3747
|
+
"workers_kv:write": "See and change Cloudflare Workers KV Storage data such as keys and namespaces",
|
|
3748
|
+
"workers_observability:read": "Grants read access to Cloudflare Workers Observability",
|
|
3749
|
+
"workers_observability:write": "Grants read and write access to Cloudflare Workers Observability",
|
|
3750
|
+
"workers_observability_telemetry:write": "Grants write access to Cloudflare Workers Observability Telemetry API",
|
|
3751
|
+
"workers_routes:write": "See and change Cloudflare Workers data such as filters and routes",
|
|
3752
|
+
"workers_scripts:write": "See and change Cloudflare Workers scripts, durable objects, subdomains, triggers, and tail data",
|
|
3753
|
+
"workers_tail:read": "See Cloudflare Workers tail and script data",
|
|
3754
|
+
"zone:read": "Grants read level access to account zone"
|
|
3755
|
+
};
|
|
3756
|
+
const DEFAULT_SCOPES = [
|
|
3757
|
+
"account:read",
|
|
3758
|
+
"ai-search:write",
|
|
3759
|
+
"ai-search:run",
|
|
3760
|
+
"ai:write",
|
|
3761
|
+
"aig:read",
|
|
3762
|
+
"aig:write",
|
|
3763
|
+
"cloudchamber:write",
|
|
3764
|
+
"connectivity:admin",
|
|
3765
|
+
"containers:write",
|
|
3766
|
+
"d1:write",
|
|
3767
|
+
"pages:write",
|
|
3768
|
+
"pipelines:write",
|
|
3769
|
+
"queues:write",
|
|
3770
|
+
"secrets_store:write",
|
|
3771
|
+
"ssl_certs:write",
|
|
3772
|
+
"user:read",
|
|
3773
|
+
"vectorize:write",
|
|
3774
|
+
"workers_kv:write",
|
|
3775
|
+
"workers_observability:read",
|
|
3776
|
+
"workers_observability:write",
|
|
3777
|
+
"workers_observability_telemetry:write",
|
|
3778
|
+
"workers_routes:write",
|
|
3779
|
+
"workers_scripts:write",
|
|
3780
|
+
"workers_tail:read",
|
|
3781
|
+
"workers:write",
|
|
3782
|
+
"zone:read"
|
|
3783
|
+
];
|
|
3784
|
+
const OAUTH_CLIENT_ID$1 = "6d8c2255-0773-45f6-b376-2914632e6f91";
|
|
3785
|
+
const OAUTH_REDIRECT_URI$1 = "http://localhost:9976/auth/callback";
|
|
3786
|
+
const OAUTH_ENDPOINTS$1 = {
|
|
3787
|
+
authorize: "https://dash.cloudflare.com/oauth2/authorize",
|
|
3788
|
+
token: "https://dash.cloudflare.com/oauth2/token",
|
|
3789
|
+
revoke: "https://dash.cloudflare.com/oauth2/revoke"
|
|
3790
|
+
};
|
|
3791
|
+
|
|
3792
|
+
//#endregion
|
|
3793
|
+
//#region lib/GitHub/AuthProvider.js
|
|
3794
|
+
init_AuthProvider();
|
|
3795
|
+
init_Credentials();
|
|
3796
|
+
const options$2 = [
|
|
3797
|
+
{
|
|
3798
|
+
value: "gh-cli",
|
|
3799
|
+
label: "GitHub CLI",
|
|
3800
|
+
hint: "delegate to `gh auth token` (run `gh auth login` first)"
|
|
3801
|
+
},
|
|
3802
|
+
{
|
|
3803
|
+
value: "env",
|
|
3804
|
+
label: "Environment Variables",
|
|
3805
|
+
hint: "GITHUB_ACCESS_TOKEN or GITHUB_TOKEN"
|
|
3806
|
+
},
|
|
3807
|
+
{
|
|
3808
|
+
value: "stored",
|
|
3809
|
+
label: "Personal Access Token",
|
|
3810
|
+
hint: "enter PAT interactively, stored in ~/.alchemy/credentials"
|
|
3811
|
+
}
|
|
3812
|
+
];
|
|
3813
|
+
const GITHUB_AUTH_PROVIDER_NAME = "GitHub";
|
|
3814
|
+
var GhCliError = class extends Error {
|
|
3815
|
+
_tag = "GhCliError";
|
|
3816
|
+
};
|
|
3817
|
+
/**
|
|
3818
|
+
* Layer that registers the GitHub {@link AuthProvider} into the
|
|
3819
|
+
* {@link AuthProviders} registry when built. Include this in the GitHub
|
|
3820
|
+
* `providers()` layer so `alchemy login` can discover it.
|
|
3821
|
+
*
|
|
3822
|
+
* Supported methods:
|
|
3823
|
+
* - `gh-cli`: shells out to `gh auth token` (recommended).
|
|
3824
|
+
* - `env`: reads `GITHUB_ACCESS_TOKEN` or `GITHUB_TOKEN`.
|
|
3825
|
+
* - `stored`: prompts for a PAT and writes it to `~/.alchemy/credentials`.
|
|
3826
|
+
*
|
|
3827
|
+
* Browser/device OAuth is intentionally not implemented: GitHub's
|
|
3828
|
+
* OAuth App flow requires a `client_secret` we cannot ship, and
|
|
3829
|
+
* device flow is exactly what `gh auth login` already does.
|
|
3830
|
+
*/
|
|
3831
|
+
const GitHubAuth = AuthProviderLayer()(GITHUB_AUTH_PROVIDER_NAME, Effect.gen(function* () {
|
|
3832
|
+
const store = yield* CredentialsStore;
|
|
3833
|
+
const cp = yield* ChildProcessSpawner;
|
|
3834
|
+
const ghCliToken = () => Effect.gen(function* () {
|
|
3835
|
+
const handle = yield* cp.spawn(ChildProcess$1.make("gh", ["auth", "token"], { shell: false }));
|
|
3836
|
+
const [exitCode, stdout, stderr] = yield* Effect.all([
|
|
3837
|
+
handle.exitCode,
|
|
3838
|
+
Stream.mkString(Stream.decodeText(handle.stdout)),
|
|
3839
|
+
Stream.mkString(Stream.decodeText(handle.stderr))
|
|
3840
|
+
], { concurrency: 3 });
|
|
3841
|
+
if (exitCode !== 0) return yield* Effect.fail(new GhCliError(`gh auth token exited with ${exitCode}: ${stderr.trim() || stdout.trim()}`));
|
|
3842
|
+
const token = stdout.trim();
|
|
3843
|
+
if (!token) return yield* Effect.fail(new GhCliError("gh auth token returned empty output"));
|
|
3844
|
+
return token;
|
|
3845
|
+
}).pipe(Effect.scoped, Effect.mapError((e) => e instanceof GhCliError ? new AuthError({
|
|
3846
|
+
message: e.message,
|
|
3847
|
+
cause: e
|
|
3848
|
+
}) : new AuthError({
|
|
3849
|
+
message: "Could not invoke `gh`. Install GitHub CLI from https://cli.github.com/ and run `gh auth login`.",
|
|
3850
|
+
cause: e
|
|
3851
|
+
})));
|
|
3852
|
+
const loginStored = Effect.fn(function* (profileName) {
|
|
3853
|
+
const token = yield* password({
|
|
3854
|
+
message: "GitHub Personal Access Token (needs `repo` scope; `workflow` for Actions)",
|
|
3855
|
+
validate: (v) => v.length === 0 ? "Required" : void 0
|
|
3856
|
+
}).pipe(retryOnce);
|
|
3857
|
+
yield* store.write(profileName, "gh-stored", {
|
|
3858
|
+
type: "pat",
|
|
3859
|
+
token
|
|
3860
|
+
});
|
|
3861
|
+
yield* success("GitHub: credentials saved.");
|
|
3862
|
+
return { method: "stored" };
|
|
3863
|
+
});
|
|
3864
|
+
const configureInteractive = (profileName) => select({
|
|
3865
|
+
message: "GitHub authentication method",
|
|
3866
|
+
options: options$2
|
|
3867
|
+
}).pipe(Effect.flatMap((method) => Match.value(method).pipe(Match.when("env", () => Effect.succeed({ method: "env" })), Match.when("gh-cli", () => ghCliToken().pipe(Effect.as({ method: "gh-cli" }), Effect.mapError((e) => new AuthError({
|
|
3868
|
+
message: `gh CLI not available: ${e.message}`,
|
|
3869
|
+
cause: e
|
|
3870
|
+
})))), Match.when("stored", () => loginStored(profileName)), Match.exhaustive)));
|
|
3871
|
+
const configureCredentials = (profileName, ctx) => Effect.gen(function* () {
|
|
3872
|
+
if (ctx.ci) return { method: "env" };
|
|
3873
|
+
return yield* configureInteractive(profileName);
|
|
3874
|
+
}).pipe(Effect.mapError((e) => new AuthError({
|
|
3875
|
+
message: "failed to configure credentials",
|
|
3876
|
+
cause: e
|
|
3877
|
+
})));
|
|
3878
|
+
const resolveCredentials = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, Effect.fn(function* () {
|
|
3879
|
+
const access = yield* getEnvRedacted("GITHUB_ACCESS_TOKEN");
|
|
3880
|
+
if (access) return {
|
|
3881
|
+
type: "token",
|
|
3882
|
+
token: access,
|
|
3883
|
+
source: {
|
|
3884
|
+
type: "env",
|
|
3885
|
+
details: "GITHUB_ACCESS_TOKEN"
|
|
3886
|
+
}
|
|
3887
|
+
};
|
|
3888
|
+
const token = yield* getEnvRedacted("GITHUB_TOKEN");
|
|
3889
|
+
if (token) return {
|
|
3890
|
+
type: "token",
|
|
3891
|
+
token,
|
|
3892
|
+
source: {
|
|
3893
|
+
type: "env",
|
|
3894
|
+
details: "GITHUB_TOKEN"
|
|
3895
|
+
}
|
|
3896
|
+
};
|
|
3897
|
+
return yield* new AuthError({ message: "GitHub env credentials not found. Set GITHUB_ACCESS_TOKEN or GITHUB_TOKEN." });
|
|
3898
|
+
})), Match.when({ method: "stored" }, () => store.read(profileName, "gh-stored").pipe(Effect.flatMap((creds) => creds == null ? Effect.fail(new AuthError({ message: "GitHub stored credentials not found. Run: alchemy login --configure" })) : Effect.succeed({
|
|
3899
|
+
type: "token",
|
|
3900
|
+
token: Redacted.make(creds.token),
|
|
3901
|
+
source: { type: "stored" }
|
|
3902
|
+
})))), Match.when({ method: "gh-cli" }, () => ghCliToken().pipe(Effect.map((token) => ({
|
|
3903
|
+
type: "token",
|
|
3904
|
+
token: Redacted.make(token),
|
|
3905
|
+
source: { type: "gh-cli" }
|
|
3906
|
+
})))), Match.exhaustive);
|
|
3907
|
+
const logout = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, () => Effect.void), Match.when({ method: "gh-cli" }, () => Effect.void), Match.when({ method: "stored" }, () => store.delete(profileName, "gh-stored").pipe(Effect.andThen(success("GitHub: stored credentials removed")))), Match.exhaustive);
|
|
3908
|
+
const login = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, () => Effect.void), Match.when({ method: "gh-cli" }, () => ghCliToken().pipe(Effect.tap(() => success("GitHub: gh CLI authentication available.")), Effect.asVoid)), Match.when({ method: "stored" }, () => store.read(profileName, "gh-stored").pipe(Effect.flatMap((creds) => creds == null ? loginStored(profileName) : Effect.void))), Match.exhaustive).pipe(Effect.mapError((e) => new AuthError({
|
|
3909
|
+
message: "login failed",
|
|
3910
|
+
cause: e
|
|
3911
|
+
})));
|
|
3912
|
+
const prettyPrint = (profileName, config) => resolveCredentials(profileName, config).pipe(Effect.tap((creds) => {
|
|
3913
|
+
const sourceStr = creds.source.details ? `${creds.source.type} - ${creds.source.details}` : creds.source.type;
|
|
3914
|
+
return Effect.all([Console.log(` token: ${displayRedacted(creds.token, 6)}`), Console.log(` source: ${sourceStr}`)]);
|
|
3915
|
+
}));
|
|
3916
|
+
return {
|
|
3917
|
+
configure: configureCredentials,
|
|
3918
|
+
logout,
|
|
3919
|
+
login,
|
|
3920
|
+
prettyPrint,
|
|
3921
|
+
read: resolveCredentials
|
|
3922
|
+
};
|
|
3923
|
+
}));
|
|
3924
|
+
|
|
3925
|
+
//#endregion
|
|
3926
|
+
//#region lib/Neon/AuthProvider.js
|
|
3927
|
+
init_AuthProvider();
|
|
3928
|
+
init_Credentials();
|
|
3929
|
+
init_Profile();
|
|
3930
|
+
const NEON_AUTH_PROVIDER_NAME = "Neon";
|
|
3931
|
+
const options$1 = [{
|
|
3932
|
+
value: "env",
|
|
3933
|
+
label: "Environment Variable",
|
|
3934
|
+
hint: "NEON_API_KEY"
|
|
3935
|
+
}, {
|
|
3936
|
+
value: "stored",
|
|
3937
|
+
label: "API Key",
|
|
3938
|
+
hint: "enter interactively, stored in ~/.alchemy/credentials"
|
|
3939
|
+
}];
|
|
3940
|
+
/**
|
|
3941
|
+
* Layer that registers the Neon {@link AuthProvider} into the
|
|
3942
|
+
* {@link AuthProviders} registry.
|
|
3943
|
+
*/
|
|
3944
|
+
const NeonAuth = AuthProviderLayer()(NEON_AUTH_PROVIDER_NAME, Effect.gen(function* () {
|
|
3945
|
+
const profiles = yield* AlchemyProfile;
|
|
3946
|
+
const store = yield* CredentialsStore;
|
|
3947
|
+
const loginStored = Effect.fn(function* (profileName) {
|
|
3948
|
+
const apiKey = yield* password({
|
|
3949
|
+
message: "Neon API Key",
|
|
3950
|
+
validate: (v) => v.length === 0 ? "Required" : void 0
|
|
3951
|
+
}).pipe(retryOnce);
|
|
3952
|
+
yield* store.write(profileName, "neon-stored", {
|
|
3953
|
+
type: "apiKey",
|
|
3954
|
+
apiKey
|
|
3955
|
+
});
|
|
3956
|
+
yield* success("Neon: credentials saved.");
|
|
3957
|
+
return { method: "stored" };
|
|
3958
|
+
});
|
|
3959
|
+
const configureInteractive = (profileName) => select({
|
|
3960
|
+
message: "Neon authentication method",
|
|
3961
|
+
options: options$1
|
|
3962
|
+
}).pipe(Effect.flatMap((method) => Match.value(method).pipe(Match.when("env", () => Effect.succeed({ method: "env" })), Match.when("stored", () => loginStored(profileName)), Match.exhaustive)));
|
|
3963
|
+
const configureCredentials = (profileName, ctx) => Effect.gen(function* () {
|
|
3964
|
+
if (ctx.ci) return { method: "env" };
|
|
3965
|
+
return yield* configureInteractive(profileName);
|
|
3966
|
+
}).pipe(Effect.mapError((e) => new AuthError({
|
|
3967
|
+
message: "failed to configure credentials",
|
|
3968
|
+
cause: e
|
|
3969
|
+
})));
|
|
3970
|
+
const resolveCredentials = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, Effect.fn(function* () {
|
|
3971
|
+
const apiKey = yield* getEnvRedacted("NEON_API_KEY");
|
|
3972
|
+
if (!apiKey) return yield* new AuthError({ message: "Neon env credentials not found. Set NEON_API_KEY." });
|
|
3973
|
+
return {
|
|
3974
|
+
type: "apiKey",
|
|
3975
|
+
apiKey,
|
|
3976
|
+
source: { type: "env" }
|
|
3977
|
+
};
|
|
3978
|
+
})), Match.when({ method: "stored" }, () => store.read(profileName, "neon-stored").pipe(Effect.flatMap((creds) => creds == null ? Effect.fail(new AuthError({ message: "Neon stored credentials not found. Run: alchemy login --configure" })) : Effect.succeed({
|
|
3979
|
+
type: "apiKey",
|
|
3980
|
+
apiKey: Redacted.make(creds.apiKey),
|
|
3981
|
+
source: { type: "stored" }
|
|
3982
|
+
})))), Match.exhaustive);
|
|
3983
|
+
const logout = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, () => Effect.void), Match.when({ method: "stored" }, () => store.delete(profileName, "neon-stored").pipe(Effect.andThen(success("Neon: stored credentials removed")))), Match.exhaustive);
|
|
3984
|
+
const login = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, () => getEnvRedacted("NEON_API_KEY").pipe(Effect.flatMap((apiKey) => apiKey ? Effect.void : Effect.gen(function* () {
|
|
3985
|
+
const next = yield* configureInteractive(profileName);
|
|
3986
|
+
const existing = yield* profiles.getProfile(profileName);
|
|
3987
|
+
yield* profiles.setProfile(profileName, {
|
|
3988
|
+
...existing,
|
|
3989
|
+
[NEON_AUTH_PROVIDER_NAME]: next
|
|
3990
|
+
});
|
|
3991
|
+
})))), Match.when({ method: "stored" }, () => store.read(profileName, "neon-stored").pipe(Effect.flatMap((creds) => creds == null ? loginStored(profileName) : Effect.void))), Match.exhaustive).pipe(Effect.mapError((e) => new AuthError({
|
|
3992
|
+
message: "login failed",
|
|
3993
|
+
cause: e
|
|
3994
|
+
})));
|
|
3995
|
+
const prettyPrint = (profileName, config) => resolveCredentials(profileName, config).pipe(Effect.tap((creds) => {
|
|
3996
|
+
const sourceStr = creds.source.details ? `${creds.source.type} - ${creds.source.details}` : creds.source.type;
|
|
3997
|
+
return Effect.all([Console.log(` apiKey: ${displayRedacted(creds.apiKey, 9)}`), Console.log(` source: ${sourceStr}`)]);
|
|
3998
|
+
}));
|
|
3999
|
+
return {
|
|
4000
|
+
configure: configureCredentials,
|
|
4001
|
+
logout,
|
|
4002
|
+
login,
|
|
4003
|
+
prettyPrint,
|
|
4004
|
+
read: resolveCredentials
|
|
4005
|
+
};
|
|
4006
|
+
}));
|
|
4007
|
+
|
|
4008
|
+
//#endregion
|
|
4009
|
+
//#region lib/Planetscale/OAuthClient.js
|
|
4010
|
+
init_AuthProvider();
|
|
4011
|
+
var OAuthError = class extends Data.TaggedError("OAuthError") {};
|
|
4012
|
+
/**
|
|
4013
|
+
* Registered PlanetScale OAuth application credentials.
|
|
4014
|
+
*
|
|
4015
|
+
* Unlike Cloudflare, PlanetScale OAuth has **no public-client flow** — the
|
|
4016
|
+
* token endpoint requires client authentication for every grant (PKCE is
|
|
4017
|
+
* advertised in their discovery doc but does not lift that requirement), so
|
|
4018
|
+
* exchanging the authorization code (and refreshing the token) requires the
|
|
4019
|
+
* application's `client_secret`. There is no way to keep that secret out of
|
|
4020
|
+
* a distributed CLI, so it ships here: the exposure is the same posture as a
|
|
4021
|
+
* public `client_id` (a stolen refresh token is usable, exactly like
|
|
4022
|
+
* Cloudflare's secret-less refresh), and it can be rotated by cutting a new
|
|
4023
|
+
* release. PlanetScale's own CLI ships its OAuth `client_secret` in source
|
|
4024
|
+
* the same way:
|
|
4025
|
+
* https://github.com/planetscale/cli/blob/main/internal/auth/authenticator.go
|
|
4026
|
+
*
|
|
4027
|
+
* Registered at https://app.planetscale.com with redirect URI
|
|
4028
|
+
* {@link OAUTH_REDIRECT_URI}. Scopes are configured on the application
|
|
4029
|
+
* itself, not requested per-authorization. Rotate by registering a new
|
|
4030
|
+
* secret and cutting a release.
|
|
4031
|
+
*/
|
|
4032
|
+
const OAUTH_CLIENT_ID = "pscale_app_aa12e3938baebb788aac443f66e422da";
|
|
4033
|
+
const OAUTH_CLIENT_SECRET = "pscale_app_secret_yyZ3Q8oe99GP9_yA5wrA5er6RuN6Lz9dC66Bj1OJzpg";
|
|
4034
|
+
const OAUTH_REDIRECT_URI = "http://localhost:9976/auth/callback";
|
|
4035
|
+
const OAUTH_ENDPOINTS = {
|
|
4036
|
+
authorize: "https://app.planetscale.com/oauth/authorize",
|
|
4037
|
+
token: "https://auth.planetscale.com/oauth/token"
|
|
4038
|
+
};
|
|
4039
|
+
function generateState(length = 32) {
|
|
4040
|
+
return crypto$1.randomBytes(length).toString("base64url");
|
|
4041
|
+
}
|
|
4042
|
+
function extractCredentials(json) {
|
|
4043
|
+
return {
|
|
4044
|
+
type: "oauth",
|
|
4045
|
+
access: json.access_token,
|
|
4046
|
+
refresh: json.refresh_token,
|
|
4047
|
+
expires: Date.now() + json.expires_in * 1e3,
|
|
4048
|
+
scopes: json.scope ? json.scope.split(" ") : []
|
|
4049
|
+
};
|
|
4050
|
+
}
|
|
4051
|
+
const tokenRequest = (params) => Effect.gen(function* () {
|
|
4052
|
+
const url = new URL(OAUTH_ENDPOINTS.token);
|
|
4053
|
+
for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
|
|
4054
|
+
const res = yield* Effect.tryPromise({
|
|
4055
|
+
try: () => fetch(url.toString(), {
|
|
4056
|
+
method: "POST",
|
|
4057
|
+
headers: { Accept: "application/json" }
|
|
4058
|
+
}),
|
|
4059
|
+
catch: (err) => new OAuthError({
|
|
4060
|
+
error: "network_error",
|
|
4061
|
+
errorDescription: `Token request failed: ${err}`
|
|
4062
|
+
})
|
|
4063
|
+
});
|
|
4064
|
+
if (!res.ok) {
|
|
4065
|
+
const json = yield* Effect.tryPromise({
|
|
4066
|
+
try: () => res.json(),
|
|
4067
|
+
catch: () => new OAuthError({
|
|
4068
|
+
error: "parse_error",
|
|
4069
|
+
errorDescription: `Token endpoint returned ${res.status}`
|
|
4070
|
+
})
|
|
4071
|
+
});
|
|
4072
|
+
return yield* new OAuthError({
|
|
4073
|
+
error: json.error,
|
|
4074
|
+
errorDescription: json.error_description
|
|
4075
|
+
});
|
|
4076
|
+
}
|
|
4077
|
+
return extractCredentials(yield* Effect.tryPromise({
|
|
4078
|
+
try: () => res.json(),
|
|
4079
|
+
catch: () => new OAuthError({
|
|
4080
|
+
error: "parse_error",
|
|
4081
|
+
errorDescription: "Failed to parse token response"
|
|
4082
|
+
})
|
|
4083
|
+
}));
|
|
4084
|
+
});
|
|
4085
|
+
/**
|
|
4086
|
+
* Generate a PlanetScale authorization URL.
|
|
4087
|
+
*
|
|
4088
|
+
* No `scope` parameter is sent: PlanetScale scopes are configured on the
|
|
4089
|
+
* OAuth application itself, not requested per-authorization, so the
|
|
4090
|
+
* consent screen shows whatever the app is registered with.
|
|
4091
|
+
*/
|
|
4092
|
+
function authorize() {
|
|
4093
|
+
const state = generateState();
|
|
4094
|
+
const url = new URL(OAUTH_ENDPOINTS.authorize);
|
|
4095
|
+
url.searchParams.set("client_id", OAUTH_CLIENT_ID);
|
|
4096
|
+
url.searchParams.set("redirect_uri", OAUTH_REDIRECT_URI);
|
|
4097
|
+
url.searchParams.set("response_type", "code");
|
|
4098
|
+
url.searchParams.set("state", state);
|
|
4099
|
+
return {
|
|
4100
|
+
url: url.toString(),
|
|
4101
|
+
state
|
|
4102
|
+
};
|
|
4103
|
+
}
|
|
4104
|
+
/**
|
|
4105
|
+
* Exchange an authorization code for OAuth credentials.
|
|
4106
|
+
*/
|
|
4107
|
+
const exchange = (code) => tokenRequest({
|
|
4108
|
+
grant_type: "authorization_code",
|
|
4109
|
+
code,
|
|
4110
|
+
client_id: OAUTH_CLIENT_ID,
|
|
4111
|
+
client_secret: OAUTH_CLIENT_SECRET,
|
|
4112
|
+
redirect_uri: OAUTH_REDIRECT_URI
|
|
4113
|
+
});
|
|
4114
|
+
/**
|
|
4115
|
+
* Refresh expired OAuth credentials.
|
|
4116
|
+
*/
|
|
4117
|
+
const refresh = (credentials) => tokenRequest({
|
|
4118
|
+
grant_type: "refresh_token",
|
|
4119
|
+
refresh_token: credentials.refresh,
|
|
4120
|
+
client_id: OAUTH_CLIENT_ID,
|
|
4121
|
+
client_secret: OAUTH_CLIENT_SECRET
|
|
4122
|
+
});
|
|
4123
|
+
/**
|
|
4124
|
+
* Start a local HTTP server to listen for the OAuth callback, exchange
|
|
4125
|
+
* the authorization code, and return the credentials.
|
|
4126
|
+
*
|
|
4127
|
+
* Times out after 5 minutes.
|
|
4128
|
+
*/
|
|
4129
|
+
const callback = (authorization) => Effect.tryPromise({
|
|
4130
|
+
try: () => callbackPromise(authorization),
|
|
4131
|
+
catch: (err) => {
|
|
4132
|
+
if (err instanceof OAuthError) return err;
|
|
4133
|
+
return new OAuthError({
|
|
4134
|
+
error: "callback_error",
|
|
4135
|
+
errorDescription: `OAuth callback failed: ${err}`
|
|
4136
|
+
});
|
|
4137
|
+
}
|
|
4138
|
+
});
|
|
4139
|
+
function callbackPromise(authorization) {
|
|
4140
|
+
const { pathname, port } = new URL(OAUTH_REDIRECT_URI);
|
|
4141
|
+
return new Promise((resolve, reject) => {
|
|
4142
|
+
const server = http.createServer(async (req, res) => {
|
|
4143
|
+
const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
|
|
4144
|
+
if (url.pathname !== pathname) {
|
|
4145
|
+
res.statusCode = 404;
|
|
4146
|
+
res.end("Not Found");
|
|
4147
|
+
return;
|
|
4148
|
+
}
|
|
4149
|
+
const error = url.searchParams.get("error");
|
|
4150
|
+
const errorDescription = url.searchParams.get("error_description");
|
|
4151
|
+
if (error) {
|
|
4152
|
+
res.writeHead(302, { Location: AUTH_ERROR_URL });
|
|
4153
|
+
res.end();
|
|
4154
|
+
cleanup();
|
|
4155
|
+
reject(new OAuthError({
|
|
4156
|
+
error,
|
|
4157
|
+
errorDescription: errorDescription ?? "An unknown error occurred."
|
|
4158
|
+
}));
|
|
4159
|
+
return;
|
|
4160
|
+
}
|
|
4161
|
+
const code = url.searchParams.get("code");
|
|
4162
|
+
const state = url.searchParams.get("state");
|
|
4163
|
+
if (!code || !state) {
|
|
4164
|
+
res.writeHead(302, { Location: AUTH_ERROR_URL });
|
|
4165
|
+
res.end();
|
|
4166
|
+
cleanup();
|
|
4167
|
+
reject(new OAuthError({
|
|
4168
|
+
error: "invalid_request",
|
|
4169
|
+
errorDescription: "Missing code or state"
|
|
4170
|
+
}));
|
|
4171
|
+
return;
|
|
4172
|
+
}
|
|
4173
|
+
if (state !== authorization.state) {
|
|
4174
|
+
res.writeHead(302, { Location: AUTH_ERROR_URL });
|
|
4175
|
+
res.end();
|
|
4176
|
+
cleanup();
|
|
4177
|
+
reject(new OAuthError({
|
|
4178
|
+
error: "invalid_request",
|
|
4179
|
+
errorDescription: "Invalid state"
|
|
4180
|
+
}));
|
|
4181
|
+
return;
|
|
4182
|
+
}
|
|
4183
|
+
try {
|
|
4184
|
+
const credentials = await Effect.runPromise(exchange(code));
|
|
4185
|
+
res.writeHead(302, { Location: AUTH_SUCCESS_URL });
|
|
4186
|
+
res.end();
|
|
4187
|
+
cleanup();
|
|
4188
|
+
resolve(credentials);
|
|
4189
|
+
} catch (err) {
|
|
4190
|
+
res.writeHead(302, { Location: AUTH_ERROR_URL });
|
|
4191
|
+
res.end();
|
|
4192
|
+
cleanup();
|
|
4193
|
+
reject(err);
|
|
4194
|
+
}
|
|
4195
|
+
});
|
|
4196
|
+
const timeout = setTimeout(() => {
|
|
4197
|
+
cleanup();
|
|
4198
|
+
reject(new OAuthError({
|
|
4199
|
+
error: "timeout",
|
|
4200
|
+
errorDescription: "The authorization process timed out."
|
|
4201
|
+
}));
|
|
4202
|
+
}, 300 * 1e3);
|
|
4203
|
+
function cleanup() {
|
|
4204
|
+
clearTimeout(timeout);
|
|
4205
|
+
server.close();
|
|
4206
|
+
}
|
|
4207
|
+
server.on("error", (err) => {
|
|
4208
|
+
cleanup();
|
|
4209
|
+
reject(new OAuthError({
|
|
4210
|
+
error: "server_error",
|
|
4211
|
+
errorDescription: `Failed to start callback server: ${err.message}`
|
|
4212
|
+
}));
|
|
4213
|
+
});
|
|
4214
|
+
server.listen(Number(port));
|
|
4215
|
+
});
|
|
4216
|
+
}
|
|
4217
|
+
|
|
4218
|
+
//#endregion
|
|
4219
|
+
//#region lib/Planetscale/AuthProvider.js
|
|
4220
|
+
init_AuthProvider();
|
|
4221
|
+
init_Credentials();
|
|
4222
|
+
/**
|
|
4223
|
+
* Canonical name registered in {@link AuthProviders}. Use this key to look
|
|
4224
|
+
* up the PlanetScale {@link AuthProvider} from inside provider Layers.
|
|
4225
|
+
*/
|
|
4226
|
+
const PLANETSCALE_AUTH_PROVIDER_NAME = "Planetscale";
|
|
4227
|
+
/**
|
|
4228
|
+
* Provide PlanetScale `Credentials` + `HttpClient` to an Effect using a
|
|
4229
|
+
* just-obtained OAuth access token. Used during configure to call
|
|
4230
|
+
* org-discovery endpoints before the user has chosen an org.
|
|
4231
|
+
*
|
|
4232
|
+
* `organization` is required by the credential type but isn't consulted by
|
|
4233
|
+
* `listOrganizations` (it's a user-scoped endpoint), so an empty string is
|
|
4234
|
+
* fine here.
|
|
4235
|
+
*/
|
|
4236
|
+
const withOAuthCredentials = (accessToken, effect) => Effect.provide(effect, Layer.mergeAll(PsCredentialsModule.fromOAuth({
|
|
4237
|
+
accessToken,
|
|
4238
|
+
organization: ""
|
|
4239
|
+
}), FetchHttpClient.layer));
|
|
4240
|
+
/**
|
|
4241
|
+
* List the organizations the OAuth user belongs to and either auto-pick
|
|
4242
|
+
* (one org) or prompt the user to choose. Returns the org's URL slug
|
|
4243
|
+
* (`name` field, used as `{organization}` in API paths).
|
|
4244
|
+
*/
|
|
4245
|
+
const selectOrganization = (accessToken) => Effect.gen(function* () {
|
|
4246
|
+
const orgs = (yield* (yield* listOrganizations)({})).data;
|
|
4247
|
+
if (orgs.length === 0) return yield* new AuthError({ message: "Planetscale: no organizations found for this credential." });
|
|
4248
|
+
if (orgs.length === 1) {
|
|
4249
|
+
const org = orgs[0];
|
|
4250
|
+
yield* info(`Planetscale: using organization: ${org.name} (${org.id})`);
|
|
4251
|
+
return org.name;
|
|
4252
|
+
}
|
|
4253
|
+
return yield* select({
|
|
4254
|
+
message: "Select a Planetscale organization",
|
|
4255
|
+
options: orgs.map((o) => ({
|
|
4256
|
+
value: o.name,
|
|
4257
|
+
label: o.name,
|
|
4258
|
+
hint: o.id
|
|
4259
|
+
}))
|
|
4260
|
+
}).pipe(retryOnce);
|
|
4261
|
+
}).pipe((e) => withOAuthCredentials(accessToken, e));
|
|
4262
|
+
const options = [
|
|
4263
|
+
{
|
|
4264
|
+
value: "env",
|
|
4265
|
+
label: "Environment Variables",
|
|
4266
|
+
hint: "PLANETSCALE_API_TOKEN_ID + PLANETSCALE_API_TOKEN + PLANETSCALE_ORGANIZATION"
|
|
4267
|
+
},
|
|
4268
|
+
{
|
|
4269
|
+
value: "oauth",
|
|
4270
|
+
label: "OAuth",
|
|
4271
|
+
hint: "recommended — browser-based login with automatic token refresh"
|
|
4272
|
+
},
|
|
4273
|
+
{
|
|
4274
|
+
value: "stored",
|
|
4275
|
+
label: "Service Token",
|
|
4276
|
+
hint: "enter service token interactively, stored in ~/.alchemy/credentials"
|
|
4277
|
+
}
|
|
4278
|
+
];
|
|
4279
|
+
/**
|
|
4280
|
+
* Layer that registers the PlanetScale {@link AuthProvider} into the
|
|
4281
|
+
* {@link AuthProviders} registry when built. Include this in the
|
|
4282
|
+
* PlanetScale `providers()` layer so `alchemy login` can discover it.
|
|
4283
|
+
*
|
|
4284
|
+
* Supported methods:
|
|
4285
|
+
* - `env`: reads `PLANETSCALE_API_TOKEN_ID`/`PLANETSCALE_API_TOKEN`/`PLANETSCALE_ORGANIZATION`.
|
|
4286
|
+
* - `stored`: prompts for a service token interactively and writes it to
|
|
4287
|
+
* `~/.alchemy/credentials/<profile>/planetscale-stored.json`.
|
|
4288
|
+
* - `oauth`: browser-based login storing access/refresh tokens at
|
|
4289
|
+
* `~/.alchemy/credentials/<profile>/planetscale-oauth.json`.
|
|
4290
|
+
*/
|
|
4291
|
+
const PlanetscaleAuth = AuthProviderLayer()(PLANETSCALE_AUTH_PROVIDER_NAME, Effect.gen(function* () {
|
|
4292
|
+
const store = yield* CredentialsStore;
|
|
4293
|
+
const oauthLogin = (profileName) => Effect.gen(function* () {
|
|
4294
|
+
const authorization = authorize();
|
|
4295
|
+
yield* info("Planetscale: opening browser for OAuth login...");
|
|
4296
|
+
yield* info(authorization.url);
|
|
4297
|
+
yield* openUrl(authorization.url).pipe(Effect.catch(() => warn("Planetscale: could not open browser automatically. Please open the URL above manually.")));
|
|
4298
|
+
yield* info("Planetscale: waiting for authorization (up to 5 minutes)...");
|
|
4299
|
+
const credentials = yield* callback(authorization);
|
|
4300
|
+
yield* store.write(profileName, "planetscale-oauth", credentials);
|
|
4301
|
+
yield* success("Planetscale: OAuth credentials saved.");
|
|
4302
|
+
return credentials;
|
|
4303
|
+
});
|
|
4304
|
+
const configureOAuth = Effect.fn(function* (profileName) {
|
|
4305
|
+
return {
|
|
4306
|
+
method: "oauth",
|
|
4307
|
+
organization: yield* selectOrganization((yield* oauthLogin(profileName)).access).pipe(Effect.catch((e) => Effect.gen(function* () {
|
|
4308
|
+
yield* warn(`Planetscale: could not auto-list organizations (${String(e)}). Falling back to manual entry.`);
|
|
4309
|
+
return yield* text({
|
|
4310
|
+
message: "Planetscale Organization (URL slug)",
|
|
4311
|
+
validate: (v) => v.length === 0 ? "Required" : void 0
|
|
4312
|
+
}).pipe(retryOnce);
|
|
4313
|
+
})))
|
|
4314
|
+
};
|
|
4315
|
+
});
|
|
4316
|
+
const loginStored = Effect.fn(function* (profileName) {
|
|
4317
|
+
const tokenId = yield* text({
|
|
4318
|
+
message: "Planetscale Service Token ID",
|
|
4319
|
+
validate: (v) => v.length === 0 ? "Required" : void 0
|
|
4320
|
+
}).pipe(retryOnce);
|
|
4321
|
+
const token = yield* password({
|
|
4322
|
+
message: "Planetscale Service Token",
|
|
4323
|
+
validate: (v) => v.length === 0 ? "Required" : void 0
|
|
4324
|
+
}).pipe(retryOnce);
|
|
4325
|
+
const organization = yield* text({
|
|
4326
|
+
message: "Planetscale Organization (URL slug)",
|
|
4327
|
+
validate: (v) => v.length === 0 ? "Required" : void 0
|
|
4328
|
+
}).pipe(retryOnce);
|
|
4329
|
+
yield* store.write(profileName, "planetscale-stored", {
|
|
4330
|
+
type: "apiToken",
|
|
4331
|
+
tokenId,
|
|
4332
|
+
token,
|
|
4333
|
+
organization
|
|
4334
|
+
});
|
|
4335
|
+
yield* success("Planetscale: credentials saved.");
|
|
4336
|
+
return { method: "stored" };
|
|
4337
|
+
});
|
|
4338
|
+
const configureInteractive = (profileName) => select({
|
|
4339
|
+
message: "Planetscale authentication method",
|
|
4340
|
+
options
|
|
4341
|
+
}).pipe(Effect.flatMap((method) => Match.value(method).pipe(Match.when("env", () => Effect.succeed({ method: "env" })), Match.when("oauth", () => configureOAuth(profileName)), Match.when("stored", () => loginStored(profileName)), Match.exhaustive)));
|
|
4342
|
+
const configureCredentials = (profileName, ctx) => Effect.gen(function* () {
|
|
4343
|
+
if (ctx.ci) return { method: "env" };
|
|
4344
|
+
return yield* configureInteractive(profileName);
|
|
4345
|
+
}).pipe(Effect.mapError((e) => new AuthError({
|
|
4346
|
+
message: "failed to configure credentials",
|
|
4347
|
+
cause: e
|
|
4348
|
+
})));
|
|
4349
|
+
const resolveCredentials = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, Effect.fn(function* () {
|
|
4350
|
+
return {
|
|
4351
|
+
type: "apiToken",
|
|
4352
|
+
tokenId: yield* getEnvRedactedRequired("PLANETSCALE_API_TOKEN_ID"),
|
|
4353
|
+
token: yield* getEnvRedactedRequired("PLANETSCALE_API_TOKEN"),
|
|
4354
|
+
organization: yield* getEnvRequired("PLANETSCALE_ORGANIZATION"),
|
|
4355
|
+
source: {
|
|
4356
|
+
type: "env",
|
|
4357
|
+
details: "PLANETSCALE_API_TOKEN_ID/PLANETSCALE_API_TOKEN"
|
|
4358
|
+
}
|
|
4359
|
+
};
|
|
4360
|
+
})), Match.when({ method: "stored" }, () => store.read(profileName, "planetscale-stored").pipe(Effect.flatMap((creds) => creds == null ? Effect.fail(new AuthError({ message: "Planetscale stored credentials not found. Run: alchemy login --configure" })) : Effect.succeed({
|
|
4361
|
+
type: "apiToken",
|
|
4362
|
+
tokenId: Redacted.make(creds.tokenId),
|
|
4363
|
+
token: Redacted.make(creds.token),
|
|
4364
|
+
organization: creds.organization,
|
|
4365
|
+
source: {
|
|
4366
|
+
type: "stored",
|
|
4367
|
+
details: void 0
|
|
4368
|
+
}
|
|
4369
|
+
})))), Match.when({ method: "oauth" }, (cfg) => Effect.gen(function* () {
|
|
4370
|
+
const creds = yield* store.read(profileName, "planetscale-oauth");
|
|
4371
|
+
if (creds == null || creds.type !== "oauth") return yield* Effect.fail(new AuthError({ message: "Planetscale OAuth credentials not found. Run: alchemy login" }));
|
|
4372
|
+
const fresh = creds.expires > Date.now() + 1e4 ? creds : yield* refresh(creds).pipe(Effect.tap((refreshed) => store.write(profileName, "planetscale-oauth", refreshed)), Effect.mapError((e) => new AuthError({
|
|
4373
|
+
message: "Planetscale OAuth refresh failed. Run: alchemy login",
|
|
4374
|
+
cause: e
|
|
4375
|
+
})));
|
|
4376
|
+
return {
|
|
4377
|
+
type: "oauth",
|
|
4378
|
+
accessToken: Redacted.make(fresh.access),
|
|
4379
|
+
expires: fresh.expires,
|
|
4380
|
+
organization: cfg.organization,
|
|
4381
|
+
source: { type: "oauth" }
|
|
4382
|
+
};
|
|
4383
|
+
})), Match.exhaustive);
|
|
4384
|
+
const logout = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, () => Effect.void), Match.when({ method: "stored" }, () => store.delete(profileName, "planetscale-stored").pipe(Effect.andThen(success("Planetscale: stored credentials removed")))), Match.when({ method: "oauth" }, () => store.delete(profileName, "planetscale-oauth").pipe(Effect.andThen(success("Planetscale: OAuth credentials removed.")))), Match.exhaustive);
|
|
4385
|
+
const login = (profileName, config) => Match.value(config).pipe(Match.when({ method: "env" }, () => Effect.void), Match.when({ method: "stored" }, () => store.read(profileName, "planetscale-stored").pipe(Effect.flatMap((creds) => creds == null ? loginStored(profileName) : Effect.void))), Match.when({ method: "oauth" }, (c$1) => Effect.gen(function* () {
|
|
4386
|
+
const creds = yield* store.read(profileName, "planetscale-oauth");
|
|
4387
|
+
if (creds?.type === "oauth") {
|
|
4388
|
+
yield* info("Planetscale: refreshing OAuth credentials...");
|
|
4389
|
+
yield* refresh(creds).pipe(Effect.flatMap((refreshed) => store.write(profileName, "planetscale-oauth", refreshed).pipe(Effect.andThen(success("Planetscale: OAuth credentials refreshed.")))), Effect.catchTag("OAuthError", () => oauthLogin(profileName).pipe(Effect.asVoid)));
|
|
4390
|
+
return;
|
|
4391
|
+
}
|
|
4392
|
+
yield* oauthLogin(profileName);
|
|
4393
|
+
})), Match.exhaustive).pipe(Effect.mapError((e) => new AuthError({
|
|
4394
|
+
message: "login failed",
|
|
4395
|
+
cause: e
|
|
4396
|
+
})));
|
|
4397
|
+
const prettyPrint = (profileName, config) => resolveCredentials(profileName, config).pipe(Effect.tap((creds) => {
|
|
4398
|
+
const sourceStr = creds.source.details ? `${creds.source.type} - ${creds.source.details}` : creds.source.type;
|
|
4399
|
+
return Match.value(creds).pipe(Match.when({ type: "apiToken" }, (c$1) => Effect.all([
|
|
4400
|
+
Console.log(` tokenId: ${displayRedacted(c$1.tokenId, 3)}`),
|
|
4401
|
+
Console.log(` token: ${displayRedacted(c$1.token, 6)}`),
|
|
4402
|
+
Console.log(` organization: ${c$1.organization}`),
|
|
4403
|
+
Console.log(` source: ${sourceStr}`)
|
|
4404
|
+
])), Match.when({ type: "oauth" }, (c$1) => {
|
|
4405
|
+
const remainingMs = c$1.expires - Date.now();
|
|
4406
|
+
const expiresAt = new Date(c$1.expires).toISOString();
|
|
4407
|
+
const expiresStr = remainingMs <= 0 ? `expired (${expiresAt})` : `in ${Duration.format(Duration.millis(remainingMs))} (${expiresAt})`;
|
|
4408
|
+
return Effect.all([
|
|
4409
|
+
Console.log(` accessToken: ${displayRedacted(c$1.accessToken)}`),
|
|
4410
|
+
Console.log(` expires: ${expiresStr}`),
|
|
4411
|
+
Console.log(` organization: ${c$1.organization}`),
|
|
4412
|
+
Console.log(` source: ${sourceStr}`)
|
|
4413
|
+
]);
|
|
4414
|
+
}), Match.exhaustive);
|
|
4415
|
+
}));
|
|
4416
|
+
return {
|
|
4417
|
+
configure: configureCredentials,
|
|
4418
|
+
logout,
|
|
4419
|
+
login,
|
|
4420
|
+
prettyPrint,
|
|
4421
|
+
read: resolveCredentials
|
|
4422
|
+
};
|
|
4423
|
+
}));
|
|
4424
|
+
|
|
2540
4425
|
//#endregion
|
|
2541
4426
|
//#region lib/Cli/commands/_shared.js
|
|
2542
|
-
|
|
2543
|
-
|
|
4427
|
+
init_AuthProvider();
|
|
4428
|
+
init_Profile();
|
|
4429
|
+
init_Stack();
|
|
4430
|
+
init_Stage();
|
|
4431
|
+
init_ConfigProvider();
|
|
4432
|
+
init_FileLogger();
|
|
4433
|
+
var __rewriteRelativeImportExtension = void 0 && (void 0).__rewriteRelativeImportExtension || function(path$2, preserveJsx) {
|
|
4434
|
+
if (typeof path$2 === "string" && /^\.\.?\//.test(path$2)) return path$2.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function(m, tsx, d, ext, cm) {
|
|
2544
4435
|
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : d + ext + "." + cm.toLowerCase() + "js";
|
|
2545
4436
|
});
|
|
2546
|
-
return path$
|
|
4437
|
+
return path$2;
|
|
2547
4438
|
};
|
|
2548
4439
|
const USER = Config.string("USER").pipe(Config.orElse(() => Config.string("USERNAME")), Config.withDefault("unknown"));
|
|
2549
4440
|
const STAGE = Config.string("stage").pipe(Config.option, (a) => a, Effect.map(Option.getOrUndefined));
|
|
@@ -2556,7 +4447,10 @@ const dryRun = Flag.boolean("dry-run").pipe(Flag.withDescription("Dry run the de
|
|
|
2556
4447
|
const yes = Flag.boolean("yes").pipe(Flag.withDescription("Yes to all prompts"), Flag.withDefault(false));
|
|
2557
4448
|
const force = Flag.boolean("force").pipe(Flag.withDescription("Force updates for resources that would otherwise no-op"), Flag.withDefault(false));
|
|
2558
4449
|
const script = Argument.file("main", { mustExist: true }).pipe(Argument.withDescription("Main file to deploy, defaults to alchemy.run.ts"), Argument.withDefault("alchemy.run.ts"));
|
|
2559
|
-
const profile = Flag.string("profile").pipe(Flag.withDescription("Auth profile to use (~/.alchemy/profiles.json). Defaults to 'default'
|
|
4450
|
+
const profile = Flag.string("profile").pipe(Flag.withDescription("Auth profile to use (~/.alchemy/profiles.json). Defaults to $ALCHEMY_PROFILE or 'default'."), Flag.optional, Flag.mapEffect(Effect.fn(function* (profile$1) {
|
|
4451
|
+
if (Option.isSome(profile$1)) return profile$1.value;
|
|
4452
|
+
return yield* ALCHEMY_PROFILE.pipe(Effect.catch(() => Effect.succeed("default")));
|
|
4453
|
+
})));
|
|
2560
4454
|
const resourceFilter = Flag.string("filter").pipe(Flag.withDescription("Comma-separated logical resource IDs (e.g. Api,Sandbox). Only those resources are included."), Flag.optional, Flag.map(Option.getOrUndefined));
|
|
2561
4455
|
/**
|
|
2562
4456
|
* Wraps a CLI command handler with a top-level OpenTelemetry span
|
|
@@ -2603,7 +4497,11 @@ const printProfile = Effect.fn(function* (profile$1, stored, registry) {
|
|
|
2603
4497
|
for (const [k, v] of Object.entries(rest)) yield* Console.log(` ${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`);
|
|
2604
4498
|
continue;
|
|
2605
4499
|
}
|
|
2606
|
-
yield* provider.prettyPrint(profile$1, cfg)
|
|
4500
|
+
yield* provider.prettyPrint(profile$1, cfg).pipe(Effect.catchCause((cause) => {
|
|
4501
|
+
const error = Cause.squash(cause);
|
|
4502
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4503
|
+
return Console.log(` Failed to retrieve credentials: ${message}`);
|
|
4504
|
+
}));
|
|
2607
4505
|
}
|
|
2608
4506
|
});
|
|
2609
4507
|
const importStack = Effect.fn(function* (main) {
|
|
@@ -2612,6 +4510,59 @@ const importStack = Effect.fn(function* (main) {
|
|
|
2612
4510
|
if (!Effect.isEffect(stackEffect)) return yield* Effect.die(/* @__PURE__ */ new Error(`Main file '${main}' must export a default stack definition (export default Alchemy.Stack({...}))`));
|
|
2613
4511
|
return stackEffect;
|
|
2614
4512
|
});
|
|
4513
|
+
/**
|
|
4514
|
+
* Placeholder {@link Stack.Stack} value used while building a stack's
|
|
4515
|
+
* `providers()` layer out of band. No real resources exist yet — we only
|
|
4516
|
+
* want the layer's provider/auth registrations and cloud-environment
|
|
4517
|
+
* services, so `resources`/`bindings`/`actions` are empty and the stage is a
|
|
4518
|
+
* sentinel.
|
|
4519
|
+
*/
|
|
4520
|
+
const placeholderStack = (name) => ({
|
|
4521
|
+
actions: {},
|
|
4522
|
+
bindings: {},
|
|
4523
|
+
name,
|
|
4524
|
+
resources: {},
|
|
4525
|
+
stage: "placeholder"
|
|
4526
|
+
});
|
|
4527
|
+
/**
|
|
4528
|
+
* Import a stack entrypoint and build its `providers()` (+ `state()`) layer
|
|
4529
|
+
* out of band against placeholder {@link Stack.Stack}/{@link Stage} services,
|
|
4530
|
+
* so its `AuthProviderLayer` registrations land in an {@link AuthProviders}
|
|
4531
|
+
* registry and the built context holds every resource provider plus the
|
|
4532
|
+
* cloud-environment services their operations need.
|
|
4533
|
+
*
|
|
4534
|
+
* Shared by `alchemy login`, `alchemy profile show`, and `alchemy unsafe
|
|
4535
|
+
* nuke`. The caller decides what to do with the result — use `authProviders`
|
|
4536
|
+
* (login / profile show) or `context` (nuke) — and whether a missing/invalid
|
|
4537
|
+
* entrypoint is fatal (login / nuke let it propagate) or best-effort
|
|
4538
|
+
* (profile show wraps the call in `Effect.catchCause`).
|
|
4539
|
+
*/
|
|
4540
|
+
const buildStackProviders = Effect.fn("buildStackProviders")(function* (options$6) {
|
|
4541
|
+
const authProviders = options$6.registry ?? {};
|
|
4542
|
+
const stackEffect = yield* importStack(options$6.main);
|
|
4543
|
+
const configProvider = withProfileOverride(yield* loadConfigProvider(options$6.envFile), options$6.profile);
|
|
4544
|
+
return {
|
|
4545
|
+
authProviders,
|
|
4546
|
+
context: yield* Layer.build((stackEffect.providers ?? Layer.empty).pipe(Layer.provideMerge(stackEffect.state ?? Layer.empty), Layer.provideMerge(Layer.mergeAll(Layer.succeed(AuthProviders, authProviders), ConfigProvider.layer(configProvider), options$6.logger ?? Logger.layer([fileLogger("out")], { mergeWithExisting: true }), Layer.succeed(Stage, "placeholder"), Layer.succeed(Stack, placeholderStack(stackEffect.stackName)), options$6.extra ?? Layer.empty)))),
|
|
4547
|
+
stackEffect
|
|
4548
|
+
};
|
|
4549
|
+
});
|
|
4550
|
+
/**
|
|
4551
|
+
* The auth providers Alchemy ships with. Used as the baseline registry so
|
|
4552
|
+
* `alchemy login` works from any folder (no `alchemy.run.ts` required) and
|
|
4553
|
+
* `alchemy profile show` can pretty-print any provider a profile mentions,
|
|
4554
|
+
* even one the current stack doesn't wire up.
|
|
4555
|
+
*/
|
|
4556
|
+
const builtinAuth = Layer.mergeAll(AwsAuth, AxiomAuth, CloudflareAuth, GitHubAuth, NeonAuth, PlanetscaleAuth);
|
|
4557
|
+
/**
|
|
4558
|
+
* Build {@link builtinAuth} against `registry` so every built-in auth
|
|
4559
|
+
* provider registers itself, without importing any stack entrypoint.
|
|
4560
|
+
*/
|
|
4561
|
+
const buildBuiltinAuthProviders = Effect.fn("buildBuiltinAuthProviders")(function* (options$6) {
|
|
4562
|
+
const authProviders = options$6.registry ?? {};
|
|
4563
|
+
yield* Layer.build(Layer.provide(builtinAuth, Layer.mergeAll(Layer.succeed(AuthProviders, authProviders), ConfigProvider.layer(withProfileOverride(yield* loadConfigProvider(options$6.envFile), options$6.profile)), Logger.layer([fileLogger("out")], { mergeWithExisting: true }))));
|
|
4564
|
+
return authProviders;
|
|
4565
|
+
});
|
|
2615
4566
|
|
|
2616
4567
|
//#endregion
|
|
2617
4568
|
//#region lib/Cli/commands/deploy.js
|
|
@@ -2788,17 +4739,14 @@ const LoggingCli = Layer.succeed(Cli, Cli.of({
|
|
|
2788
4739
|
fail: 0
|
|
2789
4740
|
};
|
|
2790
4741
|
return {
|
|
2791
|
-
emit: (event) => Effect.
|
|
2792
|
-
if (event.kind === "annotate") {
|
|
2793
|
-
console.log(`${tag(event.id)} ${blue(event.message)}`);
|
|
2794
|
-
return;
|
|
2795
|
-
}
|
|
4742
|
+
emit: (event) => Effect.suspend(() => {
|
|
4743
|
+
if (event.kind === "annotate") return Console.log(`${tag(event.id)} ${blue(event.message)}`);
|
|
2796
4744
|
const id = event.bindingId ? `${event.id}/${event.bindingId}` : event.id;
|
|
2797
4745
|
const status = statusColor$1(event.status)(event.status);
|
|
2798
4746
|
const msg = event.message ? ` ${dim("—")} ${event.message}` : "";
|
|
2799
|
-
console.log(`${tag(id)} ${status}${msg}`);
|
|
2800
4747
|
if (isTerminal(event.status)) if (event.status === "fail") counts.fail++;
|
|
2801
4748
|
else counts.ok++;
|
|
4749
|
+
return Console.log(`${tag(id)} ${status}${msg}`);
|
|
2802
4750
|
}),
|
|
2803
4751
|
done: () => Console.log(`\n${bold("Done:")} ${green(`${counts.ok} succeeded`)}${counts.fail ? dim(", ") + red(`${counts.fail} failed`) : ""}`)
|
|
2804
4752
|
};
|
|
@@ -2815,15 +4763,15 @@ function buildNamespaceTree(items, actions = []) {
|
|
|
2815
4763
|
resources: [],
|
|
2816
4764
|
actions: []
|
|
2817
4765
|
};
|
|
2818
|
-
const getNode = (path$
|
|
4766
|
+
const getNode = (path$2) => {
|
|
2819
4767
|
let current = root;
|
|
2820
|
-
for (let i = 0; i < path$
|
|
2821
|
-
const segment = path$
|
|
4768
|
+
for (let i = 0; i < path$2.length; i++) {
|
|
4769
|
+
const segment = path$2[i];
|
|
2822
4770
|
let child = current.children.get(segment);
|
|
2823
4771
|
if (!child) {
|
|
2824
4772
|
child = {
|
|
2825
4773
|
id: segment,
|
|
2826
|
-
path: path$
|
|
4774
|
+
path: path$2.slice(0, i + 1),
|
|
2827
4775
|
children: /* @__PURE__ */ new Map(),
|
|
2828
4776
|
resources: [],
|
|
2829
4777
|
actions: []
|