alchemy 2.0.0-beta.62 → 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 +12 -12
- package/bin/exec.js +1959 -70
- package/bin/exec.js.map +1 -1
- package/lib/AWS/AuthProvider.js +1 -1
- package/lib/AWS/AuthProvider.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/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/Lambda/Function.d.ts.map +1 -1
- package/lib/AWS/Lambda/Function.js +13 -40
- package/lib/AWS/Lambda/Function.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/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 +40 -6
- package/lib/Apply.js.map +1 -1
- package/lib/Auth/AuthProvider.d.ts +3 -3
- package/lib/Auth/AuthProvider.d.ts.map +1 -1
- package/lib/Auth/AuthProvider.js +1 -1
- 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/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 +2 -0
- package/lib/Bundle/Vite.d.ts.map +1 -1
- package/lib/Bundle/Vite.js +24 -1
- 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 +19 -0
- package/lib/Cli/commands/_shared.d.ts.map +1 -1
- package/lib/Cli/commands/_shared.js +22 -0
- 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 +70 -12
- package/lib/Cli/commands/login.js.map +1 -1
- package/lib/Cli/commands/profile.d.ts.map +1 -1
- package/lib/Cli/commands/profile.js +7 -20
- package/lib/Cli/commands/profile.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/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/Auth/AuthProvider.js +1 -1
- package/lib/Cloudflare/Auth/AuthProvider.js.map +1 -1
- package/lib/Cloudflare/Containers/ContainerBundle.d.ts.map +1 -1
- package/lib/Cloudflare/Containers/ContainerBundle.js +11 -1
- 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/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/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/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/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/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/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/StateStore/Api.d.ts +2 -0
- 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/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/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/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/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/LocalWorkerProvider.d.ts +2 -185
- package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts.map +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 +15 -1
- package/lib/Cloudflare/Workers/Worker.d.ts.map +1 -1
- 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 +2 -1
- 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.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBridge.js +7 -2
- 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 +450 -61
- 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/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/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/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/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.js +1 -1
- package/lib/Neon/AuthProvider.js.map +1 -1
- package/lib/Plan.d.ts.map +1 -1
- package/lib/Plan.js +11 -4
- package/lib/Plan.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/Platform.d.ts.map +1 -1
- package/lib/Platform.js +11 -1
- package/lib/Platform.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/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/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/proxy-chain.js +3 -0
- package/lib/Util/proxy-chain.js.map +1 -1
- package/package.json +10 -10
- package/src/AWS/AuthProvider.ts +1 -1
- package/src/AWS/EC2/hosted.ts +2 -1
- package/src/AWS/ECS/Task.ts +2 -1
- package/src/AWS/Lambda/Function.ts +13 -47
- package/src/AWS/Lambda/MicrovmRuntimeContext.ts +11 -38
- package/src/Action.ts +39 -6
- package/src/ActionRuntimeContext.ts +68 -0
- package/src/Apply.ts +46 -8
- package/src/Auth/AuthProvider.ts +1 -1
- package/src/Auth/Lock.ts +5 -2
- package/src/Bundle/PurePlugin.ts +34 -1
- package/src/Bundle/Vite.ts +51 -1
- package/src/Cli/LoggingCli.ts +7 -4
- package/src/Cli/commands/_shared.ts +52 -0
- package/src/Cli/commands/login.ts +90 -14
- package/src/Cli/commands/profile.ts +7 -41
- 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/index.ts +2 -0
- package/src/Cloudflare/Auth/AuthProvider.ts +1 -1
- package/src/Cloudflare/Containers/ContainerBundle.ts +11 -1
- package/src/Cloudflare/Containers/ContainerPlatform.ts +14 -52
- 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/Flagship/ReadFlagsHttpClient.ts +183 -0
- package/src/Cloudflare/Flagship/ReadFlagsLocal.ts +69 -0
- package/src/Cloudflare/Flagship/index.ts +1 -0
- 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/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/BucketHttp.ts +20 -3
- package/src/Cloudflare/R2/BucketLocal.ts +47 -0
- 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/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/Vectorize/SearchIndexHttpClient.ts +183 -0
- package/src/Cloudflare/Vectorize/SearchIndexLocal.ts +70 -0
- package/src/Cloudflare/Vectorize/index.ts +1 -0
- package/src/Cloudflare/Workers/BrowserHttpClient.ts +201 -0
- package/src/Cloudflare/Workers/BrowserLocal.ts +65 -0
- package/src/Cloudflare/Workers/ConfigProvider.ts +15 -1
- package/src/Cloudflare/Workers/DurableObject.ts +227 -6
- package/src/Cloudflare/Workers/Vite.ts +93 -11
- package/src/Cloudflare/Workers/Worker.ts +19 -1
- package/src/Cloudflare/Workers/WorkerAsyncBindings.ts +6 -5
- package/src/Cloudflare/Workers/WorkerBinding.ts +20 -1
- package/src/Cloudflare/Workers/WorkerBridge.ts +12 -2
- package/src/Cloudflare/Workers/WorkerProvider.ts +664 -117
- package/src/Cloudflare/Workers/WorkerRuntimeContext.ts +14 -45
- package/src/Cloudflare/Workers/index.ts +1 -0
- package/src/Diff.ts +33 -0
- package/src/GitHub/Secrets.ts +1 -1
- package/src/GitHub/Variables.ts +1 -1
- package/src/Local/RpcSerialization.ts +6 -2
- package/src/Local/RpcSpawner.ts +21 -8
- package/src/Neon/AuthProvider.ts +1 -1
- package/src/Plan.ts +17 -4
- 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/Platform.ts +12 -3
- 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/Test/Alchemy.ts +282 -0
- package/src/Util/cached-function.ts +5 -5
- package/src/Util/proxy-chain.ts +3 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as durableObjectsApi from "@distilled.cloud/cloudflare/durable-objects";
|
|
1
2
|
import * as workers from "@distilled.cloud/cloudflare/workers";
|
|
2
3
|
import * as wfp from "@distilled.cloud/cloudflare/workers-for-platforms";
|
|
3
4
|
import * as zones from "@distilled.cloud/cloudflare/zones";
|
|
@@ -12,7 +13,7 @@ import * as crypto from "node:crypto";
|
|
|
12
13
|
import { Unowned } from "../../AdoptPolicy.ts";
|
|
13
14
|
import * as Artifacts from "../../Artifacts.ts";
|
|
14
15
|
import type { ScopedPlanStatusSession } from "../../Cli/Cli.ts";
|
|
15
|
-
import { hashDirectory } from "../../Command/Memo.ts";
|
|
16
|
+
import { hashDirectory, type MemoOptions } from "../../Command/Memo.ts";
|
|
16
17
|
import { isResolved } from "../../Diff.ts";
|
|
17
18
|
import * as ProviderLayer from "../../Local/ProviderLayer.ts";
|
|
18
19
|
import * as Provider from "../../Provider.ts";
|
|
@@ -26,7 +27,12 @@ import { readAssets, uploadAssets } from "./Assets.ts";
|
|
|
26
27
|
import { getCompatibility } from "./Compatibility.ts";
|
|
27
28
|
import { isDurableObjectExport } from "./DurableObject.ts";
|
|
28
29
|
import { LocalWorkerProvider } from "./LocalWorkerProvider.ts";
|
|
29
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
Worker,
|
|
32
|
+
type ViteOptions,
|
|
33
|
+
type WorkerProps,
|
|
34
|
+
type WorkerRouteConfig,
|
|
35
|
+
} from "./Worker.ts";
|
|
30
36
|
import { getCacheBinding, getCronBindings } from "./WorkerAsyncBindings.ts";
|
|
31
37
|
import type { WorkerBinding, WorkerSettingsBinding } from "./WorkerBinding.ts";
|
|
32
38
|
import { readPrebuiltWorkerBundle, WorkerBundle } from "./WorkerBundle.ts";
|
|
@@ -37,6 +43,65 @@ class MissingDurableObjects extends Data.TaggedError("MissingDurableObjects")<{
|
|
|
37
43
|
expected: string[];
|
|
38
44
|
}> {}
|
|
39
45
|
|
|
46
|
+
/**
|
|
47
|
+
* A Durable Object class is being dropped from this Worker while a binding in
|
|
48
|
+
* the same deploy still references it on another script — the class moved
|
|
49
|
+
* cross-script, but its namespace (and every stored object in it) still lives
|
|
50
|
+
* on this Worker. Cloudflare rejects a single upload that both deletes the
|
|
51
|
+
* class and ships a binding referencing it, and silently deleting would
|
|
52
|
+
* destroy the namespace's data irreversibly, so the deploy fails before any
|
|
53
|
+
* upload.
|
|
54
|
+
*
|
|
55
|
+
* Moving a Durable Object class between Workers is always declared: set
|
|
56
|
+
* `transferredFrom` on the Durable Object at its **new host** — naming the
|
|
57
|
+
* former host by Worker logical id (same stack) or physical script name — and
|
|
58
|
+
* Alchemy performs the data-preserving `transferred_classes` migration on the
|
|
59
|
+
* new host's deploy; this deploy then converges on its own. To abandon the
|
|
60
|
+
* data instead, remove the binding entirely in one deploy (which deletes the
|
|
61
|
+
* class and its data), then add the cross-script binding in a second deploy.
|
|
62
|
+
*/
|
|
63
|
+
export class DurableObjectTransferRequired extends Data.TaggedError(
|
|
64
|
+
"DurableObjectTransferRequired",
|
|
65
|
+
)<{
|
|
66
|
+
scriptName: string;
|
|
67
|
+
className: string;
|
|
68
|
+
targetScriptName: string | undefined;
|
|
69
|
+
}> {
|
|
70
|
+
override get message() {
|
|
71
|
+
return (
|
|
72
|
+
`Durable Object class '${this.className}' still lives on Worker '${this.scriptName}' but this deploy re-binds it as a cross-script reference` +
|
|
73
|
+
(this.targetScriptName ? ` to '${this.targetScriptName}'` : "") +
|
|
74
|
+
". Durable Object data does NOT move with the class automatically. " +
|
|
75
|
+
`To move the data, set transferredFrom: "${this.scriptName}" (the former host's script name, or its Worker logical id for same-stack moves) on the Durable Object declaration in its new host Worker. ` +
|
|
76
|
+
"To abandon the data, remove the binding entirely in one deploy before re-adding it as a cross-script reference."
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* More than one script matches the `transferredFrom` declaration of a Durable
|
|
83
|
+
* Object (e.g. an orphaned script left behind by a `name` prop change still
|
|
84
|
+
* carries the same alchemy tags, or the host history lists several scripts
|
|
85
|
+
* that each still hold a same-class namespace). Alchemy refuses to guess
|
|
86
|
+
* which namespace's data to move — narrow the declaration to the exact
|
|
87
|
+
* physical script name that holds the data.
|
|
88
|
+
*/
|
|
89
|
+
export class AmbiguousDurableObjectTransfer extends Data.TaggedError(
|
|
90
|
+
"AmbiguousDurableObjectTransfer",
|
|
91
|
+
)<{
|
|
92
|
+
scriptName: string;
|
|
93
|
+
logicalId: string;
|
|
94
|
+
className: string;
|
|
95
|
+
sources: string[];
|
|
96
|
+
}> {
|
|
97
|
+
override get message() {
|
|
98
|
+
return (
|
|
99
|
+
`Durable Object '${this.logicalId}' (class '${this.className}') is new to Worker '${this.scriptName}' and multiple scripts match its transferredFrom declaration: ${this.sources.join(", ")}. ` +
|
|
100
|
+
`Narrow transferredFrom to the exact physical script name that holds the data.`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
40
105
|
/**
|
|
41
106
|
* Resolve the Workers for Platforms dispatch-namespace *name* from a resolved
|
|
42
107
|
* `namespace` prop or persisted attribute. The engine resolves a passed
|
|
@@ -895,6 +960,79 @@ export const LiveWorkerProvider = () =>
|
|
|
895
960
|
return createAlchemyWorkerTags(id).every((tag) => actualTags.has(tag));
|
|
896
961
|
};
|
|
897
962
|
|
|
963
|
+
/**
|
|
964
|
+
* Resolve the source script of a declared Durable Object transfer for
|
|
965
|
+
* a class that is new to `selfScriptName`. `sources` is the
|
|
966
|
+
* `transferredFrom` host history: each entry names a former host either
|
|
967
|
+
* by *physical script name* or by *Worker logical id* in this stack +
|
|
968
|
+
* stage (matched via the `alchemy:id:`/stack/stage ownership tags).
|
|
969
|
+
* The namespace is transferred from whichever listed host currently
|
|
970
|
+
* holds a same-class namespace; when none does (fresh stage, or every
|
|
971
|
+
* transfer already completed) this returns `undefined` and the caller
|
|
972
|
+
* creates the class fresh — the declaration is inert and safe to keep.
|
|
973
|
+
* More than one match (e.g. an orphaned script from a `name` change)
|
|
974
|
+
* fails with {@link AmbiguousDurableObjectTransfer} rather than
|
|
975
|
+
* guessing whose data to move.
|
|
976
|
+
*/
|
|
977
|
+
const resolveTransferSource = Effect.fn(function* (params: {
|
|
978
|
+
accountId: string;
|
|
979
|
+
selfScriptName: string;
|
|
980
|
+
logicalId: string;
|
|
981
|
+
className: string;
|
|
982
|
+
sources: readonly string[];
|
|
983
|
+
observedNamespaces: readonly { script: string; class: string }[];
|
|
984
|
+
}) {
|
|
985
|
+
if (params.sources.length === 0) {
|
|
986
|
+
return undefined;
|
|
987
|
+
}
|
|
988
|
+
const candidates = Array.from(
|
|
989
|
+
new Set(
|
|
990
|
+
params.observedNamespaces.flatMap((ns) =>
|
|
991
|
+
ns.class === params.className &&
|
|
992
|
+
ns.script !== params.selfScriptName
|
|
993
|
+
? [ns.script]
|
|
994
|
+
: [],
|
|
995
|
+
),
|
|
996
|
+
),
|
|
997
|
+
);
|
|
998
|
+
const matched: string[] = [];
|
|
999
|
+
for (const script of candidates) {
|
|
1000
|
+
if (params.sources.includes(script)) {
|
|
1001
|
+
matched.push(script);
|
|
1002
|
+
continue;
|
|
1003
|
+
}
|
|
1004
|
+
const settings = yield* getScriptSettings(
|
|
1005
|
+
params.accountId,
|
|
1006
|
+
script,
|
|
1007
|
+
undefined,
|
|
1008
|
+
).pipe(
|
|
1009
|
+
Effect.catchTag("WorkerNotFound", () => Effect.succeed(undefined)),
|
|
1010
|
+
Effect.catchTag("WorkerHasNoVersions", () =>
|
|
1011
|
+
Effect.succeed(undefined),
|
|
1012
|
+
),
|
|
1013
|
+
);
|
|
1014
|
+
const tags = new Set(settings?.tags ?? []);
|
|
1015
|
+
if (
|
|
1016
|
+
tags.has(`alchemy:stack:${stack.name}`) &&
|
|
1017
|
+
tags.has(`alchemy:stage:${stack.stage}`) &&
|
|
1018
|
+
params.sources.some((source) => tags.has(`alchemy:id:${source}`))
|
|
1019
|
+
) {
|
|
1020
|
+
matched.push(script);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
if (matched.length > 1) {
|
|
1024
|
+
return yield* Effect.fail(
|
|
1025
|
+
new AmbiguousDurableObjectTransfer({
|
|
1026
|
+
scriptName: params.selfScriptName,
|
|
1027
|
+
logicalId: params.logicalId,
|
|
1028
|
+
className: params.className,
|
|
1029
|
+
sources: matched,
|
|
1030
|
+
}),
|
|
1031
|
+
);
|
|
1032
|
+
}
|
|
1033
|
+
return matched[0];
|
|
1034
|
+
});
|
|
1035
|
+
|
|
898
1036
|
const getDurableObjects = (
|
|
899
1037
|
bindings: readonly WorkerSettingsBinding[] | null | undefined,
|
|
900
1038
|
) => {
|
|
@@ -1031,41 +1169,42 @@ export const LiveWorkerProvider = () =>
|
|
|
1031
1169
|
// (~0.5s), which is only needed for vite-based workers at build time —
|
|
1032
1170
|
// not for every Worker definition at module-load time.
|
|
1033
1171
|
const Vite = yield* Effect.promise(() => import("./Vite.ts"));
|
|
1034
|
-
const { clientDirectory, serverBundle } =
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
//
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1172
|
+
const { clientDirectory, serverBundle, externalWorkspaces } =
|
|
1173
|
+
yield* Vite.viteBuild(
|
|
1174
|
+
props.vite?.rootDir,
|
|
1175
|
+
Object.fromEntries(
|
|
1176
|
+
(yield* Effect.all(
|
|
1177
|
+
Object.entries(props.env ?? {}).map(
|
|
1178
|
+
Effect.fn(function* ([key, value]) {
|
|
1179
|
+
return [
|
|
1180
|
+
key,
|
|
1181
|
+
typeof value === "string"
|
|
1182
|
+
? value
|
|
1183
|
+
: Redacted.isRedacted(value) &&
|
|
1184
|
+
typeof Redacted.value(value) === "string"
|
|
1185
|
+
? Redacted.value(value)
|
|
1186
|
+
: // A `WorkerLoader` is a real Effect that also carries
|
|
1187
|
+
// the `~alchemy/Kind` marker — it is a binding, not a
|
|
1188
|
+
// runnable env value. Check it before `Effect.isEffect`
|
|
1189
|
+
// so we don't execute it as an inlined env entry.
|
|
1190
|
+
isWorkerLoader(value)
|
|
1191
|
+
? undefined
|
|
1192
|
+
: Effect.isEffect(value)
|
|
1193
|
+
? yield* value as any as Effect.Effect<any>
|
|
1194
|
+
: undefined,
|
|
1195
|
+
];
|
|
1196
|
+
}),
|
|
1197
|
+
),
|
|
1198
|
+
)).filter(([_, value]) => value !== undefined),
|
|
1199
|
+
),
|
|
1200
|
+
{
|
|
1201
|
+
main: props.vite?.main,
|
|
1202
|
+
compatibilityDate: compatibility.date,
|
|
1203
|
+
compatibilityFlags: compatibility.flags,
|
|
1204
|
+
viteEnvironments: props.vite?.viteEnvironments,
|
|
1205
|
+
},
|
|
1206
|
+
);
|
|
1207
|
+
const [assets, bundle, input] = yield* Effect.all(
|
|
1069
1208
|
[
|
|
1070
1209
|
clientDirectory
|
|
1071
1210
|
? readAssets({
|
|
@@ -1079,6 +1218,11 @@ export const LiveWorkerProvider = () =>
|
|
|
1079
1218
|
})
|
|
1080
1219
|
: Effect.undefined,
|
|
1081
1220
|
serverBundle,
|
|
1221
|
+
hashViteInput(
|
|
1222
|
+
props.vite?.rootDir,
|
|
1223
|
+
props.vite?.memo,
|
|
1224
|
+
externalWorkspaces,
|
|
1225
|
+
),
|
|
1082
1226
|
],
|
|
1083
1227
|
{ concurrency: "unbounded" },
|
|
1084
1228
|
);
|
|
@@ -1087,7 +1231,56 @@ export const LiveWorkerProvider = () =>
|
|
|
1087
1231
|
new Error("Vite build produced neither assets nor server output"),
|
|
1088
1232
|
);
|
|
1089
1233
|
}
|
|
1090
|
-
return {
|
|
1234
|
+
return {
|
|
1235
|
+
assets,
|
|
1236
|
+
bundle,
|
|
1237
|
+
input: input.hash,
|
|
1238
|
+
additionalWorkspaces: input.workspaces,
|
|
1239
|
+
};
|
|
1240
|
+
});
|
|
1241
|
+
|
|
1242
|
+
const hashViteInput = Effect.fn(function* <E>(
|
|
1243
|
+
rootDir: string = process.cwd(),
|
|
1244
|
+
options: ViteOptions["memo"],
|
|
1245
|
+
additionalWorkspaces: Effect.Effect<Iterable<string>, E>,
|
|
1246
|
+
) {
|
|
1247
|
+
const hashWorkspaceDirectory = (cwd: string, memo?: MemoOptions) =>
|
|
1248
|
+
hashDirectory({ cwd: path.resolve(rootDir, cwd), memo }).pipe(
|
|
1249
|
+
Effect.map((hash) => `${path.relative(rootDir, cwd)}:${hash}`),
|
|
1250
|
+
);
|
|
1251
|
+
const hashRoot = hashWorkspaceDirectory(rootDir, options);
|
|
1252
|
+
if (Array.isArray(options?.workspaces)) {
|
|
1253
|
+
return yield* Effect.all(
|
|
1254
|
+
[
|
|
1255
|
+
hashRoot,
|
|
1256
|
+
...options.workspaces.map(({ cwd, ...options }) =>
|
|
1257
|
+
hashWorkspaceDirectory(cwd, options),
|
|
1258
|
+
),
|
|
1259
|
+
],
|
|
1260
|
+
{ concurrency: "unbounded" },
|
|
1261
|
+
).pipe(
|
|
1262
|
+
Effect.flatMap(([root, ...workspaces]) =>
|
|
1263
|
+
sha256Object([root, ...workspaces.sort()]),
|
|
1264
|
+
),
|
|
1265
|
+
Effect.map((hash) => ({ hash, workspaces: undefined })),
|
|
1266
|
+
);
|
|
1267
|
+
}
|
|
1268
|
+
const [root, workspaces] = yield* Effect.all(
|
|
1269
|
+
[hashRoot, additionalWorkspaces],
|
|
1270
|
+
{ concurrency: "unbounded" },
|
|
1271
|
+
);
|
|
1272
|
+
const workspaceHashes = yield* Effect.forEach(
|
|
1273
|
+
workspaces,
|
|
1274
|
+
(cwd) => hashWorkspaceDirectory(cwd),
|
|
1275
|
+
{ concurrency: "unbounded" },
|
|
1276
|
+
);
|
|
1277
|
+
const hash = yield* sha256Object([root, ...workspaceHashes.sort()]);
|
|
1278
|
+
return {
|
|
1279
|
+
hash,
|
|
1280
|
+
workspaces: Array.from(workspaces).map((cwd) =>
|
|
1281
|
+
path.relative(rootDir, cwd),
|
|
1282
|
+
),
|
|
1283
|
+
};
|
|
1091
1284
|
});
|
|
1092
1285
|
|
|
1093
1286
|
const prepareAssetsAndBundle = (
|
|
@@ -1112,27 +1305,12 @@ export const LiveWorkerProvider = () =>
|
|
|
1112
1305
|
files: [{ path: "main.js", content: props.script }],
|
|
1113
1306
|
hash: bundleHash,
|
|
1114
1307
|
},
|
|
1308
|
+
input: undefined,
|
|
1309
|
+
additionalWorkspaces: undefined,
|
|
1115
1310
|
};
|
|
1116
1311
|
}
|
|
1117
1312
|
if (props.vite) {
|
|
1118
|
-
|
|
1119
|
-
[
|
|
1120
|
-
viteBuild(props),
|
|
1121
|
-
// hashDirectory expects `{ cwd, memo }`. The vite props
|
|
1122
|
-
// store the project root under `rootDir`, so map it
|
|
1123
|
-
// here. Without this, `cwd` falls back to
|
|
1124
|
-
// `process.cwd()` and the input hash is computed over
|
|
1125
|
-
// the wrong directory tree (often the entire monorepo
|
|
1126
|
-
// root), making it both slow and unable to detect
|
|
1127
|
-
// changes scoped to the actual Vite project.
|
|
1128
|
-
hashDirectory({
|
|
1129
|
-
cwd: props.vite.rootDir,
|
|
1130
|
-
memo: props.vite.memo,
|
|
1131
|
-
}),
|
|
1132
|
-
],
|
|
1133
|
-
{ concurrency: "unbounded" },
|
|
1134
|
-
);
|
|
1135
|
-
return { assets, bundle, input };
|
|
1313
|
+
return yield* viteBuild(props);
|
|
1136
1314
|
}
|
|
1137
1315
|
const [assets, bundle] = yield* Effect.all(
|
|
1138
1316
|
[
|
|
@@ -1143,9 +1321,14 @@ export const LiveWorkerProvider = () =>
|
|
|
1143
1321
|
],
|
|
1144
1322
|
{ concurrency: "unbounded" },
|
|
1145
1323
|
);
|
|
1146
|
-
return {
|
|
1324
|
+
return {
|
|
1325
|
+
assets,
|
|
1326
|
+
bundle,
|
|
1327
|
+
input: undefined,
|
|
1328
|
+
additionalWorkspaces: undefined,
|
|
1329
|
+
};
|
|
1147
1330
|
}).pipe(
|
|
1148
|
-
Effect.map(({ assets, bundle, input }) => ({
|
|
1331
|
+
Effect.map(({ assets, bundle, input, additionalWorkspaces }) => ({
|
|
1149
1332
|
assets,
|
|
1150
1333
|
bundle: {
|
|
1151
1334
|
main: bundle?.files[0].path,
|
|
@@ -1160,6 +1343,7 @@ export const LiveWorkerProvider = () =>
|
|
|
1160
1343
|
assets: assets?.hash,
|
|
1161
1344
|
bundle: bundle?.hash,
|
|
1162
1345
|
input,
|
|
1346
|
+
additionalWorkspaces,
|
|
1163
1347
|
} satisfies Worker["Attributes"]["hash"],
|
|
1164
1348
|
})),
|
|
1165
1349
|
);
|
|
@@ -1222,7 +1406,22 @@ export const LiveWorkerProvider = () =>
|
|
|
1222
1406
|
assets: prebuiltAssets?.hash ?? preparedHash.assets,
|
|
1223
1407
|
metadata: metadataHash,
|
|
1224
1408
|
} satisfies Worker["Attributes"]["hash"];
|
|
1225
|
-
|
|
1409
|
+
// `transferredFrom` is alchemy-only transfer metadata on
|
|
1410
|
+
// durable_object_namespace bindings — it drives the
|
|
1411
|
+
// `transferred_classes` migration below and must be stripped from the
|
|
1412
|
+
// wire-shape binding before upload.
|
|
1413
|
+
const metadataBindings = bindings.flatMap((b) =>
|
|
1414
|
+
(b.data.bindings ?? []).map((item): WorkerBinding => {
|
|
1415
|
+
if (
|
|
1416
|
+
item.type === "durable_object_namespace" &&
|
|
1417
|
+
item.transferredFrom !== undefined
|
|
1418
|
+
) {
|
|
1419
|
+
const { transferredFrom: _, ...rest } = item;
|
|
1420
|
+
return rest;
|
|
1421
|
+
}
|
|
1422
|
+
return item;
|
|
1423
|
+
}),
|
|
1424
|
+
);
|
|
1226
1425
|
const expectedDurableObjectClassNames =
|
|
1227
1426
|
getExpectedDurableObjectClassNames(metadataBindings, name);
|
|
1228
1427
|
let metadataAssets:
|
|
@@ -1355,7 +1554,8 @@ export const LiveWorkerProvider = () =>
|
|
|
1355
1554
|
const oldTags = Array.from(new Set(oldSettings?.tags ?? []));
|
|
1356
1555
|
const oldBindings = oldSettings?.bindings ?? [];
|
|
1357
1556
|
|
|
1358
|
-
// Parse
|
|
1557
|
+
// Parse the DO logical-id→class mapping from script tags (packed
|
|
1558
|
+
// `alchemy:dos:` and legacy per-DO `alchemy:do:` formats)
|
|
1359
1559
|
const oldDoClassNameByLogicalId = getDurableObjectTagMap(oldTags);
|
|
1360
1560
|
const currentDoBindings = getDurableObjectBindings(bindings, name);
|
|
1361
1561
|
const currentDoClassNameByLogicalId = Object.fromEntries(
|
|
@@ -1373,13 +1573,15 @@ export const LiveWorkerProvider = () =>
|
|
|
1373
1573
|
)[0];
|
|
1374
1574
|
const newMigrationTag = bumpMigrationTagVersion(oldMigrationTag);
|
|
1375
1575
|
|
|
1376
|
-
// Compute
|
|
1377
|
-
|
|
1576
|
+
// Compute delete-class candidates. Candidates are validated against
|
|
1577
|
+
// observed namespace ownership below — a class may already have been
|
|
1578
|
+
// transferred to another script by its new host's deploy.
|
|
1579
|
+
const deletedClassCandidates: string[] = [];
|
|
1378
1580
|
for (const [logicalId, className] of Object.entries(
|
|
1379
1581
|
oldDoClassNameByLogicalId,
|
|
1380
1582
|
)) {
|
|
1381
1583
|
if (!currentDoClassNameByLogicalId[logicalId]) {
|
|
1382
|
-
|
|
1584
|
+
deletedClassCandidates.push(className);
|
|
1383
1585
|
}
|
|
1384
1586
|
}
|
|
1385
1587
|
|
|
@@ -1401,11 +1603,107 @@ export const LiveWorkerProvider = () =>
|
|
|
1401
1603
|
(binding) => binding.bindingName === oldBinding.name,
|
|
1402
1604
|
)
|
|
1403
1605
|
) {
|
|
1404
|
-
|
|
1606
|
+
deletedClassCandidates.push(oldBinding.className);
|
|
1405
1607
|
}
|
|
1406
1608
|
}
|
|
1407
1609
|
}
|
|
1408
1610
|
|
|
1611
|
+
// Class names the current deploy references *cross-script* (mapped to
|
|
1612
|
+
// the foreign script). A class that both leaves the "hosted here" set
|
|
1613
|
+
// and shows up here has moved to another Worker — Cloudflare rejects
|
|
1614
|
+
// deleting a class while any binding in the upload references its
|
|
1615
|
+
// class name, and deleting would destroy the namespace's data.
|
|
1616
|
+
const crossScriptClassTargets = new Map<string, string>();
|
|
1617
|
+
for (const item of metadataBindings) {
|
|
1618
|
+
if (
|
|
1619
|
+
item.type === "durable_object_namespace" &&
|
|
1620
|
+
item.className &&
|
|
1621
|
+
typeof item.scriptName === "string" &&
|
|
1622
|
+
item.scriptName !== name
|
|
1623
|
+
) {
|
|
1624
|
+
crossScriptClassTargets.set(item.className, item.scriptName);
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
// One account-level namespace listing serves both sides of a
|
|
1629
|
+
// transfer: the destination checks the source still hosts the class
|
|
1630
|
+
// before emitting `transferred_classes`, and the former host checks
|
|
1631
|
+
// whether a to-be-deleted class was already transferred away.
|
|
1632
|
+
// Dispatch-namespace user workers keep the legacy behavior — their
|
|
1633
|
+
// namespaces don't surface on the account-level list.
|
|
1634
|
+
const mayTransferIn = currentDoBindings.some(
|
|
1635
|
+
(binding) =>
|
|
1636
|
+
!oldDoClassNameByLogicalId[binding.logicalId] &&
|
|
1637
|
+
binding.transferredFrom !== undefined,
|
|
1638
|
+
);
|
|
1639
|
+
const observedNamespaces =
|
|
1640
|
+
!dispatchNamespace &&
|
|
1641
|
+
(deletedClassCandidates.length > 0 || mayTransferIn)
|
|
1642
|
+
? yield* listDurableObjectNamespaces(accountId)
|
|
1643
|
+
: [];
|
|
1644
|
+
const hosts = (
|
|
1645
|
+
namespaces: readonly { script: string; class: string }[],
|
|
1646
|
+
scriptName: string,
|
|
1647
|
+
className: string,
|
|
1648
|
+
) =>
|
|
1649
|
+
namespaces.some(
|
|
1650
|
+
(ns) => ns.script === scriptName && ns.class === className,
|
|
1651
|
+
);
|
|
1652
|
+
const scriptHostsClass = (scriptName: string, className: string) =>
|
|
1653
|
+
hosts(observedNamespaces, scriptName, className);
|
|
1654
|
+
|
|
1655
|
+
const deletedClasses: string[] = [];
|
|
1656
|
+
for (const className of deletedClassCandidates) {
|
|
1657
|
+
if (dispatchNamespace) {
|
|
1658
|
+
deletedClasses.push(className);
|
|
1659
|
+
continue;
|
|
1660
|
+
}
|
|
1661
|
+
const targetScriptName = crossScriptClassTargets.get(className);
|
|
1662
|
+
if (targetScriptName === undefined) {
|
|
1663
|
+
// Plain removal. Delete only if the namespace actually still
|
|
1664
|
+
// lives here — it may have been transferred to another script by
|
|
1665
|
+
// that script's deploy, or removed out-of-band. The stale
|
|
1666
|
+
// alchemy:do tag drops out either way because tags are recomputed
|
|
1667
|
+
// from current bindings.
|
|
1668
|
+
if (scriptHostsClass(name, className)) {
|
|
1669
|
+
deletedClasses.push(className);
|
|
1670
|
+
}
|
|
1671
|
+
continue;
|
|
1672
|
+
}
|
|
1673
|
+
// The class went local → cross-script. When the new host's deploy
|
|
1674
|
+
// ran a `transferred_classes` migration moments ago, the account
|
|
1675
|
+
// listing can briefly still attribute the namespace to this script,
|
|
1676
|
+
// so re-observe with a short bounded budget until the transfer
|
|
1677
|
+
// becomes visible (namespace off this script) or the state is
|
|
1678
|
+
// conclusively a conflict (still here — including the case where
|
|
1679
|
+
// the target created a *fresh* namespace for the same class name).
|
|
1680
|
+
const namespaces = yield* listDurableObjectNamespaces(accountId).pipe(
|
|
1681
|
+
Effect.repeat({
|
|
1682
|
+
schedule: Schedule.spaced("2 seconds"),
|
|
1683
|
+
until: (observed) =>
|
|
1684
|
+
!hosts(observed, name, className) ||
|
|
1685
|
+
hosts(observed, targetScriptName, className),
|
|
1686
|
+
times: 5,
|
|
1687
|
+
}),
|
|
1688
|
+
);
|
|
1689
|
+
if (!hosts(namespaces, name, className)) {
|
|
1690
|
+
// Transferred away — nothing to delete.
|
|
1691
|
+
continue;
|
|
1692
|
+
}
|
|
1693
|
+
// local → cross-script transition without a transfer. Fail before
|
|
1694
|
+
// any upload: Cloudflare would reject the combined delete + binding
|
|
1695
|
+
// anyway, and silently deleting would destroy the namespace's
|
|
1696
|
+
// data. See the error's docs for the two ways out
|
|
1697
|
+
// (`transferredFrom` on the new host, or a two-phase removal).
|
|
1698
|
+
return yield* Effect.fail(
|
|
1699
|
+
new DurableObjectTransferRequired({
|
|
1700
|
+
scriptName: name,
|
|
1701
|
+
className,
|
|
1702
|
+
targetScriptName,
|
|
1703
|
+
}),
|
|
1704
|
+
);
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1409
1707
|
// Collect container-backed class names so we can send container metadata
|
|
1410
1708
|
const containerClassNames = new Set(
|
|
1411
1709
|
bindings.flatMap((b) =>
|
|
@@ -1413,27 +1711,42 @@ export const LiveWorkerProvider = () =>
|
|
|
1413
1711
|
),
|
|
1414
1712
|
);
|
|
1415
1713
|
|
|
1416
|
-
// Compute new and
|
|
1714
|
+
// Compute new, renamed, and transferred classes
|
|
1417
1715
|
const newClasses: string[] = [];
|
|
1418
1716
|
const newSqliteClasses: string[] = [];
|
|
1419
1717
|
const renamedClasses: { from: string; to: string }[] = [];
|
|
1718
|
+
const transferredClasses: {
|
|
1719
|
+
from: string;
|
|
1720
|
+
fromScript: string;
|
|
1721
|
+
to: string;
|
|
1722
|
+
}[] = [];
|
|
1420
1723
|
for (const binding of currentDoBindings) {
|
|
1421
1724
|
let previousClassName: string | undefined =
|
|
1422
1725
|
oldDoClassNameByLogicalId[binding.logicalId];
|
|
1423
1726
|
if (!previousClassName) {
|
|
1424
|
-
// No
|
|
1727
|
+
// No DO metadata tag maps this logical id to a class — the
|
|
1425
1728
|
// worker was created outside Alchemy (raw API / Wrangler) or
|
|
1426
1729
|
// before these tags existed. Fall back to matching the observed
|
|
1427
1730
|
// cloud binding by binding name so adoption reuses the existing
|
|
1428
1731
|
// class instead of asking Cloudflare to create one that already
|
|
1429
1732
|
// exists (which fails the migration). This is the "first deploy
|
|
1430
1733
|
// must match the existing class name" path; once we write the
|
|
1431
|
-
// `alchemy:
|
|
1734
|
+
// `alchemy:dos:` tag, subsequent renames are driven by logical id.
|
|
1432
1735
|
const observed = oldBindings.find(
|
|
1433
1736
|
(old) =>
|
|
1434
1737
|
old.type === "durable_object_namespace" &&
|
|
1435
1738
|
"className" in old &&
|
|
1436
1739
|
old.className &&
|
|
1740
|
+
// Only a *locally-owned* binding proves the class exists on
|
|
1741
|
+
// this script. A cross-script binding under the same name —
|
|
1742
|
+
// e.g. this worker previously referenced another host's
|
|
1743
|
+
// class and now hosts its own — points at a foreign
|
|
1744
|
+
// namespace and must not suppress the create migration
|
|
1745
|
+
// (Cloudflare rejects a local binding for a class the
|
|
1746
|
+
// script isn't configured to implement).
|
|
1747
|
+
(!("scriptName" in old) ||
|
|
1748
|
+
old.scriptName === undefined ||
|
|
1749
|
+
old.scriptName === name) &&
|
|
1437
1750
|
old.name === binding.bindingName,
|
|
1438
1751
|
);
|
|
1439
1752
|
if (observed && "className" in observed && observed.className) {
|
|
@@ -1441,6 +1754,38 @@ export const LiveWorkerProvider = () =>
|
|
|
1441
1754
|
}
|
|
1442
1755
|
}
|
|
1443
1756
|
if (!previousClassName) {
|
|
1757
|
+
// A class new to this script is a host move when the declaration
|
|
1758
|
+
// says so: `transferredFrom` lists the former host(s) — moves
|
|
1759
|
+
// are always declared, never inferred, because a class deleted
|
|
1760
|
+
// on one worker and created on another is otherwise ambiguous
|
|
1761
|
+
// between "move the data" and "delete + fresh namespace". The
|
|
1762
|
+
// declared source must be observed to still host the namespace;
|
|
1763
|
+
// otherwise (fresh stage, transfer already completed) fall
|
|
1764
|
+
// through to a plain create.
|
|
1765
|
+
const fromScript = dispatchNamespace
|
|
1766
|
+
? undefined
|
|
1767
|
+
: yield* resolveTransferSource({
|
|
1768
|
+
accountId,
|
|
1769
|
+
selfScriptName: name,
|
|
1770
|
+
logicalId: binding.logicalId,
|
|
1771
|
+
className: binding.className,
|
|
1772
|
+
sources: normalizeTransferSources(
|
|
1773
|
+
binding.transferredFrom,
|
|
1774
|
+
name,
|
|
1775
|
+
),
|
|
1776
|
+
observedNamespaces,
|
|
1777
|
+
});
|
|
1778
|
+
if (fromScript !== undefined) {
|
|
1779
|
+
// Data-preserving move: ship Cloudflare's
|
|
1780
|
+
// `transferred_classes` migration instead of creating a
|
|
1781
|
+
// fresh class.
|
|
1782
|
+
transferredClasses.push({
|
|
1783
|
+
from: binding.className,
|
|
1784
|
+
fromScript,
|
|
1785
|
+
to: binding.className,
|
|
1786
|
+
});
|
|
1787
|
+
continue;
|
|
1788
|
+
}
|
|
1444
1789
|
// Default all new Durable Object classes to SQLite. Cloudflare
|
|
1445
1790
|
// recommends SQLite for new namespaces, and container-backed
|
|
1446
1791
|
// Durable Objects require it.
|
|
@@ -1460,29 +1805,28 @@ export const LiveWorkerProvider = () =>
|
|
|
1460
1805
|
currentDoClassNameByLogicalId,
|
|
1461
1806
|
deletedClasses,
|
|
1462
1807
|
renamedClasses,
|
|
1808
|
+
transferredClasses,
|
|
1463
1809
|
newSqliteClasses,
|
|
1464
1810
|
},
|
|
1465
1811
|
)}`,
|
|
1466
1812
|
);
|
|
1467
1813
|
|
|
1468
|
-
//
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1814
|
+
// Pack every DO logical-id→class mapping into as few `alchemy:dos:`
|
|
1815
|
+
// tags as possible — one tag per DO blows Cloudflare's 10-tag limit
|
|
1816
|
+
// at 7+ bindings (#811).
|
|
1817
|
+
const alchemyDoTags = encodeDurableObjectTags(currentDoBindings);
|
|
1818
|
+
|
|
1819
|
+
const alchemyTags = [
|
|
1820
|
+
...createAlchemyWorkerTags(id),
|
|
1821
|
+
...alchemyDoTags,
|
|
1822
|
+
...(newMigrationTag
|
|
1823
|
+
? [`alchemy:migration-tag:${newMigrationTag}`]
|
|
1824
|
+
: []),
|
|
1825
|
+
];
|
|
1476
1826
|
const metadataTags = Array.from(
|
|
1477
|
-
new Set([
|
|
1478
|
-
...createAlchemyWorkerTags(id),
|
|
1479
|
-
...alchemyDoTags,
|
|
1480
|
-
...(newMigrationTag
|
|
1481
|
-
? [`alchemy:migration-tag:${newMigrationTag}`]
|
|
1482
|
-
: []),
|
|
1483
|
-
...(news.tags ?? []),
|
|
1484
|
-
]),
|
|
1827
|
+
new Set([...alchemyTags, ...(news.tags ?? [])]),
|
|
1485
1828
|
);
|
|
1829
|
+
yield* validateWorkerTags(name, metadataTags, alchemyTags.length);
|
|
1486
1830
|
|
|
1487
1831
|
const migrations = {
|
|
1488
1832
|
oldTag: oldMigrationTag,
|
|
@@ -1490,7 +1834,7 @@ export const LiveWorkerProvider = () =>
|
|
|
1490
1834
|
newClasses,
|
|
1491
1835
|
deletedClasses,
|
|
1492
1836
|
renamedClasses,
|
|
1493
|
-
transferredClasses
|
|
1837
|
+
transferredClasses,
|
|
1494
1838
|
newSqliteClasses,
|
|
1495
1839
|
};
|
|
1496
1840
|
|
|
@@ -1733,11 +2077,12 @@ export const LiveWorkerProvider = () =>
|
|
|
1733
2077
|
return assetsHash !== output.hash?.assets;
|
|
1734
2078
|
}
|
|
1735
2079
|
if (props.vite) {
|
|
1736
|
-
const
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
2080
|
+
const { hash } = yield* hashViteInput(
|
|
2081
|
+
props.vite.rootDir,
|
|
2082
|
+
props.vite.memo,
|
|
2083
|
+
Effect.succeed(output.hash?.additionalWorkspaces ?? []),
|
|
2084
|
+
);
|
|
2085
|
+
return hash !== output.hash?.input;
|
|
1741
2086
|
}
|
|
1742
2087
|
const bundleHash = yield* prepareBundle(id, props).pipe(
|
|
1743
2088
|
Effect.map((b) => b.hash),
|
|
@@ -2009,10 +2354,17 @@ export const LiveWorkerProvider = () =>
|
|
|
2009
2354
|
const exportDerived = Object.keys(exportMap)
|
|
2010
2355
|
.filter((logicalId) => isDurableObjectExport(exportMap[logicalId]))
|
|
2011
2356
|
.map((logicalId) => ({ logicalId, className: logicalId }));
|
|
2357
|
+
// Transfer-destination classes are excluded from the placeholder
|
|
2358
|
+
// entirely (class list, bindings, tags): Cloudflare forbids
|
|
2359
|
+
// creating the destination class of a `transferred_classes`
|
|
2360
|
+
// migration ahead of the transfer, so `reconcile` must perform it
|
|
2361
|
+
// with the real upload. (`transferredFrom` may still be an
|
|
2362
|
+
// unresolved Output here — precreate runs on raw props — but only
|
|
2363
|
+
// its presence matters.)
|
|
2012
2364
|
const durableObjects = mergeDurableObjectClasses(
|
|
2013
2365
|
exportDerived,
|
|
2014
2366
|
getDurableObjectBindings(bindings, name),
|
|
2015
|
-
);
|
|
2367
|
+
).filter((binding) => !binding.transferredFrom);
|
|
2016
2368
|
const doClasses = durableObjects.map((binding) => binding.className);
|
|
2017
2369
|
// Only attach container metadata for classes actually fronted by a
|
|
2018
2370
|
// Container binding (mirrors reconcile's `containerClassNames`).
|
|
@@ -2025,17 +2377,15 @@ export const LiveWorkerProvider = () =>
|
|
|
2025
2377
|
),
|
|
2026
2378
|
),
|
|
2027
2379
|
).map((className) => ({ className }));
|
|
2028
|
-
const alchemyDoTags = durableObjects
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2380
|
+
const alchemyDoTags = encodeDurableObjectTags(durableObjects);
|
|
2381
|
+
const alchemyTags = [
|
|
2382
|
+
...createAlchemyWorkerTags(id),
|
|
2383
|
+
...alchemyDoTags,
|
|
2384
|
+
];
|
|
2032
2385
|
const tags = Array.from(
|
|
2033
|
-
new Set([
|
|
2034
|
-
...createAlchemyWorkerTags(id),
|
|
2035
|
-
...alchemyDoTags,
|
|
2036
|
-
...(news.tags ?? []),
|
|
2037
|
-
]),
|
|
2386
|
+
new Set([...alchemyTags, ...(news.tags ?? [])]),
|
|
2038
2387
|
);
|
|
2388
|
+
yield* validateWorkerTags(name, tags, alchemyTags.length);
|
|
2039
2389
|
yield* Effect.logInfo(
|
|
2040
2390
|
`Cloudflare Worker precreate: starting ${name}`,
|
|
2041
2391
|
);
|
|
@@ -2377,16 +2727,12 @@ export const LiveWorkerProvider = () =>
|
|
|
2377
2727
|
);
|
|
2378
2728
|
yield* Effect.logInfo(
|
|
2379
2729
|
`Cloudflare Worker reconcile: existing durable object tags ${JSON.stringify(
|
|
2380
|
-
(existingSettings?.tags ?? []).filter(
|
|
2381
|
-
tag.startsWith("alchemy:do:"),
|
|
2382
|
-
),
|
|
2730
|
+
(existingSettings?.tags ?? []).filter(isDurableObjectTag),
|
|
2383
2731
|
)}`,
|
|
2384
2732
|
);
|
|
2385
2733
|
yield* Effect.logInfo(
|
|
2386
2734
|
`Cloudflare Worker reconcile: previous durable object tags ${JSON.stringify(
|
|
2387
|
-
(output?.tags ?? []).filter(
|
|
2388
|
-
tag.startsWith("alchemy:do:"),
|
|
2389
|
-
),
|
|
2735
|
+
(output?.tags ?? []).filter(isDurableObjectTag),
|
|
2390
2736
|
)}`,
|
|
2391
2737
|
);
|
|
2392
2738
|
|
|
@@ -2521,6 +2867,41 @@ const contentTypeFromExtension = (extension: string) => {
|
|
|
2521
2867
|
}
|
|
2522
2868
|
};
|
|
2523
2869
|
|
|
2870
|
+
/**
|
|
2871
|
+
* Observe every Durable Object namespace on the account as `(script, class)`
|
|
2872
|
+
* pairs. Namespace ownership is authoritative cloud state: after a
|
|
2873
|
+
* `transferred_classes` migration the namespace moves to the receiving
|
|
2874
|
+
* script, so this is how both sides of a transfer observe where a class
|
|
2875
|
+
* currently lives — the destination checks the source still hosts the class
|
|
2876
|
+
* before emitting the transfer, and the former host checks whether a class
|
|
2877
|
+
* it is about to delete has already been transferred away.
|
|
2878
|
+
*/
|
|
2879
|
+
const listDurableObjectNamespaces = (accountId: string) =>
|
|
2880
|
+
durableObjectsApi.listNamespaces.items({ accountId }).pipe(
|
|
2881
|
+
Stream.runCollect,
|
|
2882
|
+
Effect.map((namespaces) =>
|
|
2883
|
+
Array.from(namespaces).flatMap((ns) =>
|
|
2884
|
+
ns.script && ns.class ? [{ script: ns.script, class: ns.class }] : [],
|
|
2885
|
+
),
|
|
2886
|
+
),
|
|
2887
|
+
);
|
|
2888
|
+
|
|
2889
|
+
/**
|
|
2890
|
+
* Coerce a resolved `transferredFrom` declaration to its list form, dropping
|
|
2891
|
+
* self-references (a worker naming itself as its own former host is
|
|
2892
|
+
* meaningless — the class already lives there).
|
|
2893
|
+
*/
|
|
2894
|
+
const normalizeTransferSources = (
|
|
2895
|
+
value: string | readonly string[] | undefined,
|
|
2896
|
+
selfScriptName: string,
|
|
2897
|
+
): string[] =>
|
|
2898
|
+
(value === undefined
|
|
2899
|
+
? []
|
|
2900
|
+
: Array.isArray(value)
|
|
2901
|
+
? value
|
|
2902
|
+
: [value as string]
|
|
2903
|
+
).filter((source) => source !== selfScriptName);
|
|
2904
|
+
|
|
2524
2905
|
function bumpMigrationTagVersion(
|
|
2525
2906
|
oldTag: string | undefined,
|
|
2526
2907
|
): string | undefined {
|
|
@@ -2533,12 +2914,20 @@ function bumpMigrationTagVersion(
|
|
|
2533
2914
|
/**
|
|
2534
2915
|
* Merges a worker's export-derived and binding-derived Durable Object class
|
|
2535
2916
|
* lists for the precreate placeholder, deduping by class name. The
|
|
2536
|
-
* binding-derived entry wins on a collision so the `alchemy:
|
|
2917
|
+
* binding-derived entry wins on a collision so the `alchemy:dos:` tag keys off
|
|
2537
2918
|
* the same logical id (the binding sid) that `reconcile` writes.
|
|
2538
2919
|
*/
|
|
2539
2920
|
function mergeDurableObjectClasses(
|
|
2540
|
-
exportDerived: ReadonlyArray<{
|
|
2541
|
-
|
|
2921
|
+
exportDerived: ReadonlyArray<{
|
|
2922
|
+
logicalId: string;
|
|
2923
|
+
className: string;
|
|
2924
|
+
transferredFrom?: string | string[];
|
|
2925
|
+
}>,
|
|
2926
|
+
bindingDerived: ReadonlyArray<{
|
|
2927
|
+
logicalId: string;
|
|
2928
|
+
className: string;
|
|
2929
|
+
transferredFrom?: string | string[];
|
|
2930
|
+
}>,
|
|
2542
2931
|
) {
|
|
2543
2932
|
return Array.from(
|
|
2544
2933
|
new Map(
|
|
@@ -2582,22 +2971,180 @@ function getDurableObjectBindings(
|
|
|
2582
2971
|
logicalId: binding.sid,
|
|
2583
2972
|
bindingName: item.name,
|
|
2584
2973
|
className: item.className,
|
|
2974
|
+
// Declared host history for a data-preserving
|
|
2975
|
+
// `transferred_classes` migration. Normalize an empty list to
|
|
2976
|
+
// "not declared"; self-references are dropped at resolution time.
|
|
2977
|
+
transferredFrom:
|
|
2978
|
+
Array.isArray(item.transferredFrom) &&
|
|
2979
|
+
item.transferredFrom.length === 0
|
|
2980
|
+
? undefined
|
|
2981
|
+
: item.transferredFrom,
|
|
2585
2982
|
},
|
|
2586
2983
|
];
|
|
2587
2984
|
}),
|
|
2588
2985
|
);
|
|
2589
2986
|
}
|
|
2590
2987
|
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2988
|
+
/**
|
|
2989
|
+
* Cloudflare Worker script-tag limits, verified empirically against the live
|
|
2990
|
+
* API (2026-07):
|
|
2991
|
+
*
|
|
2992
|
+
* - at most **10 tags** per Worker (the 11th is rejected with `Forbidden`)
|
|
2993
|
+
* - each tag is at most **1024 bytes** (`BadRequest: Tag is too large`)
|
|
2994
|
+
* - tags may not contain `,` or `&`; everything else (`:`, `;`, `=`, `/`,
|
|
2995
|
+
* spaces, unicode) is accepted and round-trips intact
|
|
2996
|
+
*
|
|
2997
|
+
* Alchemy reserves 3 ownership tags (`alchemy:stack/stage/id`) and 1
|
|
2998
|
+
* migration tag, so the Durable Object logical-id→class mapping must not
|
|
2999
|
+
* spend one tag per DO (#811). Instead all mappings are packed into as few
|
|
3000
|
+
* `alchemy:dos:` tags as possible.
|
|
3001
|
+
*/
|
|
3002
|
+
const MAX_TAGS_PER_WORKER = 10;
|
|
3003
|
+
const MAX_TAG_BYTES = 1024;
|
|
3004
|
+
const LEGACY_DO_TAG_PREFIX = "alchemy:do:";
|
|
3005
|
+
const PACKED_DO_TAG_PREFIX = "alchemy:dos:";
|
|
3006
|
+
|
|
3007
|
+
class InvalidWorkerTags extends Data.TaggedError("InvalidWorkerTags")<{
|
|
3008
|
+
scriptName: string;
|
|
3009
|
+
reason: string;
|
|
3010
|
+
}> {}
|
|
3011
|
+
|
|
3012
|
+
/**
|
|
3013
|
+
* Pack Durable Object logical-id→class mappings into `alchemy:dos:` tags.
|
|
3014
|
+
*
|
|
3015
|
+
* Each mapping is encoded as `logicalId=className` — elided to just
|
|
3016
|
+
* `className` when the two are equal (the common case for export-derived
|
|
3017
|
+
* classes) — with both components `encodeURIComponent`-escaped so the `;`
|
|
3018
|
+
* pair separator, the `=` delimiter, and Cloudflare's forbidden tag
|
|
3019
|
+
* characters (`,`, `&`) can never collide with user identifiers. Pairs are
|
|
3020
|
+
* sorted for deterministic output and greedily packed so each tag stays
|
|
3021
|
+
* within Cloudflare's 1024-byte tag limit; workers with more DOs than fit in
|
|
3022
|
+
* one tag spill into additional `alchemy:dos:` tags.
|
|
3023
|
+
*
|
|
3024
|
+
* `encodeURIComponent` output is pure ASCII, so `String.length` equals the
|
|
3025
|
+
* tag's byte length.
|
|
3026
|
+
*
|
|
3027
|
+
* @internal exported for unit testing.
|
|
3028
|
+
*/
|
|
3029
|
+
export function encodeDurableObjectTags(
|
|
3030
|
+
durableObjects: ReadonlyArray<{ logicalId: string; className: string }>,
|
|
3031
|
+
): string[] {
|
|
3032
|
+
const pairs = [...durableObjects]
|
|
3033
|
+
.sort((a, b) => a.logicalId.localeCompare(b.logicalId))
|
|
3034
|
+
.map(({ logicalId, className }) =>
|
|
3035
|
+
logicalId === className
|
|
3036
|
+
? encodeURIComponent(className)
|
|
3037
|
+
: `${encodeURIComponent(logicalId)}=${encodeURIComponent(className)}`,
|
|
3038
|
+
);
|
|
3039
|
+
const tags: string[] = [];
|
|
3040
|
+
let payload = "";
|
|
3041
|
+
for (const pair of pairs) {
|
|
3042
|
+
const appended = payload === "" ? pair : `${payload};${pair}`;
|
|
3043
|
+
if (
|
|
3044
|
+
PACKED_DO_TAG_PREFIX.length + appended.length > MAX_TAG_BYTES &&
|
|
3045
|
+
payload !== ""
|
|
3046
|
+
) {
|
|
3047
|
+
tags.push(`${PACKED_DO_TAG_PREFIX}${payload}`);
|
|
3048
|
+
payload = pair;
|
|
3049
|
+
} else {
|
|
3050
|
+
payload = appended;
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
3053
|
+
if (payload !== "") {
|
|
3054
|
+
tags.push(`${PACKED_DO_TAG_PREFIX}${payload}`);
|
|
3055
|
+
}
|
|
3056
|
+
return tags;
|
|
3057
|
+
}
|
|
3058
|
+
|
|
3059
|
+
/**
|
|
3060
|
+
* Parse the Durable Object logical-id→class mapping from a worker's script
|
|
3061
|
+
* tags. Reads both formats so workers deployed before the packed format roll
|
|
3062
|
+
* forward transparently:
|
|
3063
|
+
*
|
|
3064
|
+
* - legacy: one `alchemy:do:{logicalId}:{className}` tag per DO
|
|
3065
|
+
* - packed: `alchemy:dos:{pair};{pair};…` (see {@link encodeDurableObjectTags})
|
|
3066
|
+
*
|
|
3067
|
+
* A packed entry wins over a legacy entry for the same logical id.
|
|
3068
|
+
*
|
|
3069
|
+
* @internal exported for unit testing.
|
|
3070
|
+
*/
|
|
3071
|
+
export function getDurableObjectTagMap(tags: ReadonlyArray<string>) {
|
|
3072
|
+
const map: Record<string, string> = {};
|
|
3073
|
+
for (const tag of tags) {
|
|
3074
|
+
if (tag.startsWith(LEGACY_DO_TAG_PREFIX)) {
|
|
2597
3075
|
const parts = tag.split(":");
|
|
2598
3076
|
const logicalId = parts[2];
|
|
2599
3077
|
const className = parts.slice(3).join(":");
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
3078
|
+
if (logicalId && className && !(logicalId in map)) {
|
|
3079
|
+
map[logicalId] = className;
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
for (const tag of tags) {
|
|
3084
|
+
if (tag.startsWith(PACKED_DO_TAG_PREFIX)) {
|
|
3085
|
+
for (const pair of tag.slice(PACKED_DO_TAG_PREFIX.length).split(";")) {
|
|
3086
|
+
if (pair === "") continue;
|
|
3087
|
+
const eq = pair.indexOf("=");
|
|
3088
|
+
const logicalId = decodeURIComponent(
|
|
3089
|
+
eq === -1 ? pair : pair.slice(0, eq),
|
|
3090
|
+
);
|
|
3091
|
+
const className = decodeURIComponent(
|
|
3092
|
+
eq === -1 ? pair : pair.slice(eq + 1),
|
|
3093
|
+
);
|
|
3094
|
+
if (logicalId && className) {
|
|
3095
|
+
map[logicalId] = className;
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
return map;
|
|
2603
3101
|
}
|
|
3102
|
+
|
|
3103
|
+
const isDurableObjectTag = (tag: string) =>
|
|
3104
|
+
tag.startsWith(LEGACY_DO_TAG_PREFIX) || tag.startsWith(PACKED_DO_TAG_PREFIX);
|
|
3105
|
+
|
|
3106
|
+
/**
|
|
3107
|
+
* Fail fast — before the script upload — when a worker's tag set violates
|
|
3108
|
+
* Cloudflare's limits, instead of surfacing the raw `Forbidden`/`BadRequest`
|
|
3109
|
+
* at PUT time (#811). `alchemyTagCount` is the number of tags alchemy itself
|
|
3110
|
+
* generated (ownership + migration + packed DO tags) so the message can tell
|
|
3111
|
+
* the user how much of the budget is theirs.
|
|
3112
|
+
*/
|
|
3113
|
+
const validateWorkerTags = (
|
|
3114
|
+
scriptName: string,
|
|
3115
|
+
tags: ReadonlyArray<string>,
|
|
3116
|
+
alchemyTagCount: number,
|
|
3117
|
+
) =>
|
|
3118
|
+
Effect.gen(function* () {
|
|
3119
|
+
if (tags.length > MAX_TAGS_PER_WORKER) {
|
|
3120
|
+
return yield* Effect.fail(
|
|
3121
|
+
new InvalidWorkerTags({
|
|
3122
|
+
scriptName,
|
|
3123
|
+
reason:
|
|
3124
|
+
`worker "${scriptName}" needs ${tags.length} script tags but Cloudflare allows at most ${MAX_TAGS_PER_WORKER}. ` +
|
|
3125
|
+
`Alchemy reserves ${alchemyTagCount} (ownership, migration and durable-object metadata); ` +
|
|
3126
|
+
`${tags.length - alchemyTagCount} user tags were passed via \`tags\`. Remove ${tags.length - MAX_TAGS_PER_WORKER} tag(s).`,
|
|
3127
|
+
}),
|
|
3128
|
+
);
|
|
3129
|
+
}
|
|
3130
|
+
const encoder = new TextEncoder();
|
|
3131
|
+
for (const tag of tags) {
|
|
3132
|
+
if (tag.includes(",") || tag.includes("&")) {
|
|
3133
|
+
return yield* Effect.fail(
|
|
3134
|
+
new InvalidWorkerTags({
|
|
3135
|
+
scriptName,
|
|
3136
|
+
reason: `worker "${scriptName}" tag ${JSON.stringify(tag)} contains ',' or '&', which Cloudflare rejects.`,
|
|
3137
|
+
}),
|
|
3138
|
+
);
|
|
3139
|
+
}
|
|
3140
|
+
const bytes = yield* Effect.sync(() => encoder.encode(tag).length);
|
|
3141
|
+
if (bytes > MAX_TAG_BYTES) {
|
|
3142
|
+
return yield* Effect.fail(
|
|
3143
|
+
new InvalidWorkerTags({
|
|
3144
|
+
scriptName,
|
|
3145
|
+
reason: `worker "${scriptName}" tag ${JSON.stringify(tag.slice(0, 64))}… is ${bytes} bytes; Cloudflare allows at most ${MAX_TAG_BYTES}.`,
|
|
3146
|
+
}),
|
|
3147
|
+
);
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3150
|
+
});
|