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";
|
|
@@ -25,13 +26,53 @@ import { readAssets, uploadAssets } from "./Assets.js";
|
|
|
25
26
|
import { getCompatibility } from "./Compatibility.js";
|
|
26
27
|
import { isDurableObjectExport } from "./DurableObject.js";
|
|
27
28
|
import { LocalWorkerProvider } from "./LocalWorkerProvider.js";
|
|
28
|
-
import { Worker } from "./Worker.js";
|
|
29
|
+
import { Worker, } from "./Worker.js";
|
|
29
30
|
import { getCacheBinding, getCronBindings } from "./WorkerAsyncBindings.js";
|
|
30
31
|
import { readPrebuiltWorkerBundle, WorkerBundle } from "./WorkerBundle.js";
|
|
31
32
|
import { isWorkerLoader } from "./WorkerLoader.js";
|
|
32
33
|
import { createWorkerName } from "./WorkerName.js";
|
|
33
34
|
class MissingDurableObjects extends Data.TaggedError("MissingDurableObjects") {
|
|
34
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* A Durable Object class is being dropped from this Worker while a binding in
|
|
38
|
+
* the same deploy still references it on another script — the class moved
|
|
39
|
+
* cross-script, but its namespace (and every stored object in it) still lives
|
|
40
|
+
* on this Worker. Cloudflare rejects a single upload that both deletes the
|
|
41
|
+
* class and ships a binding referencing it, and silently deleting would
|
|
42
|
+
* destroy the namespace's data irreversibly, so the deploy fails before any
|
|
43
|
+
* upload.
|
|
44
|
+
*
|
|
45
|
+
* Moving a Durable Object class between Workers is always declared: set
|
|
46
|
+
* `transferredFrom` on the Durable Object at its **new host** — naming the
|
|
47
|
+
* former host by Worker logical id (same stack) or physical script name — and
|
|
48
|
+
* Alchemy performs the data-preserving `transferred_classes` migration on the
|
|
49
|
+
* new host's deploy; this deploy then converges on its own. To abandon the
|
|
50
|
+
* data instead, remove the binding entirely in one deploy (which deletes the
|
|
51
|
+
* class and its data), then add the cross-script binding in a second deploy.
|
|
52
|
+
*/
|
|
53
|
+
export class DurableObjectTransferRequired extends Data.TaggedError("DurableObjectTransferRequired") {
|
|
54
|
+
get message() {
|
|
55
|
+
return (`Durable Object class '${this.className}' still lives on Worker '${this.scriptName}' but this deploy re-binds it as a cross-script reference` +
|
|
56
|
+
(this.targetScriptName ? ` to '${this.targetScriptName}'` : "") +
|
|
57
|
+
". Durable Object data does NOT move with the class automatically. " +
|
|
58
|
+
`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. ` +
|
|
59
|
+
"To abandon the data, remove the binding entirely in one deploy before re-adding it as a cross-script reference.");
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* More than one script matches the `transferredFrom` declaration of a Durable
|
|
64
|
+
* Object (e.g. an orphaned script left behind by a `name` prop change still
|
|
65
|
+
* carries the same alchemy tags, or the host history lists several scripts
|
|
66
|
+
* that each still hold a same-class namespace). Alchemy refuses to guess
|
|
67
|
+
* which namespace's data to move — narrow the declaration to the exact
|
|
68
|
+
* physical script name that holds the data.
|
|
69
|
+
*/
|
|
70
|
+
export class AmbiguousDurableObjectTransfer extends Data.TaggedError("AmbiguousDurableObjectTransfer") {
|
|
71
|
+
get message() {
|
|
72
|
+
return (`Durable Object '${this.logicalId}' (class '${this.className}') is new to Worker '${this.scriptName}' and multiple scripts match its transferredFrom declaration: ${this.sources.join(", ")}. ` +
|
|
73
|
+
`Narrow transferredFrom to the exact physical script name that holds the data.`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
35
76
|
/**
|
|
36
77
|
* Resolve the Workers for Platforms dispatch-namespace *name* from a resolved
|
|
37
78
|
* `namespace` prop or persisted attribute. The engine resolves a passed
|
|
@@ -626,6 +667,52 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
626
667
|
const actualTags = new Set(tags ?? []);
|
|
627
668
|
return createAlchemyWorkerTags(id).every((tag) => actualTags.has(tag));
|
|
628
669
|
};
|
|
670
|
+
/**
|
|
671
|
+
* Resolve the source script of a declared Durable Object transfer for
|
|
672
|
+
* a class that is new to `selfScriptName`. `sources` is the
|
|
673
|
+
* `transferredFrom` host history: each entry names a former host either
|
|
674
|
+
* by *physical script name* or by *Worker logical id* in this stack +
|
|
675
|
+
* stage (matched via the `alchemy:id:`/stack/stage ownership tags).
|
|
676
|
+
* The namespace is transferred from whichever listed host currently
|
|
677
|
+
* holds a same-class namespace; when none does (fresh stage, or every
|
|
678
|
+
* transfer already completed) this returns `undefined` and the caller
|
|
679
|
+
* creates the class fresh — the declaration is inert and safe to keep.
|
|
680
|
+
* More than one match (e.g. an orphaned script from a `name` change)
|
|
681
|
+
* fails with {@link AmbiguousDurableObjectTransfer} rather than
|
|
682
|
+
* guessing whose data to move.
|
|
683
|
+
*/
|
|
684
|
+
const resolveTransferSource = Effect.fn(function* (params) {
|
|
685
|
+
if (params.sources.length === 0) {
|
|
686
|
+
return undefined;
|
|
687
|
+
}
|
|
688
|
+
const candidates = Array.from(new Set(params.observedNamespaces.flatMap((ns) => ns.class === params.className &&
|
|
689
|
+
ns.script !== params.selfScriptName
|
|
690
|
+
? [ns.script]
|
|
691
|
+
: [])));
|
|
692
|
+
const matched = [];
|
|
693
|
+
for (const script of candidates) {
|
|
694
|
+
if (params.sources.includes(script)) {
|
|
695
|
+
matched.push(script);
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
|
+
const settings = yield* getScriptSettings(params.accountId, script, undefined).pipe(Effect.catchTag("WorkerNotFound", () => Effect.succeed(undefined)), Effect.catchTag("WorkerHasNoVersions", () => Effect.succeed(undefined)));
|
|
699
|
+
const tags = new Set(settings?.tags ?? []);
|
|
700
|
+
if (tags.has(`alchemy:stack:${stack.name}`) &&
|
|
701
|
+
tags.has(`alchemy:stage:${stack.stage}`) &&
|
|
702
|
+
params.sources.some((source) => tags.has(`alchemy:id:${source}`))) {
|
|
703
|
+
matched.push(script);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
if (matched.length > 1) {
|
|
707
|
+
return yield* Effect.fail(new AmbiguousDurableObjectTransfer({
|
|
708
|
+
scriptName: params.selfScriptName,
|
|
709
|
+
logicalId: params.logicalId,
|
|
710
|
+
className: params.className,
|
|
711
|
+
sources: matched,
|
|
712
|
+
}));
|
|
713
|
+
}
|
|
714
|
+
return matched[0];
|
|
715
|
+
});
|
|
629
716
|
const getDurableObjects = (bindings) => {
|
|
630
717
|
const namespaces = Object.fromEntries((bindings ?? []).flatMap((binding) => binding.type === "durable_object_namespace" &&
|
|
631
718
|
binding.className &&
|
|
@@ -712,7 +799,7 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
712
799
|
// (~0.5s), which is only needed for vite-based workers at build time —
|
|
713
800
|
// not for every Worker definition at module-load time.
|
|
714
801
|
const Vite = yield* Effect.promise(() => import("./Vite.js"));
|
|
715
|
-
const { clientDirectory, serverBundle } = yield* Vite.viteBuild(props.vite?.rootDir, Object.fromEntries((yield* Effect.all(Object.entries(props.env ?? {}).map(Effect.fn(function* ([key, value]) {
|
|
802
|
+
const { clientDirectory, serverBundle, externalWorkspaces } = yield* Vite.viteBuild(props.vite?.rootDir, Object.fromEntries((yield* Effect.all(Object.entries(props.env ?? {}).map(Effect.fn(function* ([key, value]) {
|
|
716
803
|
return [
|
|
717
804
|
key,
|
|
718
805
|
typeof value === "string"
|
|
@@ -736,7 +823,7 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
736
823
|
compatibilityFlags: compatibility.flags,
|
|
737
824
|
viteEnvironments: props.vite?.viteEnvironments,
|
|
738
825
|
});
|
|
739
|
-
const [assets, bundle] = yield* Effect.all([
|
|
826
|
+
const [assets, bundle, input] = yield* Effect.all([
|
|
740
827
|
clientDirectory
|
|
741
828
|
? readAssets({
|
|
742
829
|
...(props.assets && typeof props.assets !== "string"
|
|
@@ -746,11 +833,34 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
746
833
|
})
|
|
747
834
|
: Effect.undefined,
|
|
748
835
|
serverBundle,
|
|
836
|
+
hashViteInput(props.vite?.rootDir, props.vite?.memo, externalWorkspaces),
|
|
749
837
|
], { concurrency: "unbounded" });
|
|
750
838
|
if (!assets && !bundle) {
|
|
751
839
|
return yield* Effect.die(new Error("Vite build produced neither assets nor server output"));
|
|
752
840
|
}
|
|
753
|
-
return {
|
|
841
|
+
return {
|
|
842
|
+
assets,
|
|
843
|
+
bundle,
|
|
844
|
+
input: input.hash,
|
|
845
|
+
additionalWorkspaces: input.workspaces,
|
|
846
|
+
};
|
|
847
|
+
});
|
|
848
|
+
const hashViteInput = Effect.fn(function* (rootDir = process.cwd(), options, additionalWorkspaces) {
|
|
849
|
+
const hashWorkspaceDirectory = (cwd, memo) => hashDirectory({ cwd: path.resolve(rootDir, cwd), memo }).pipe(Effect.map((hash) => `${path.relative(rootDir, cwd)}:${hash}`));
|
|
850
|
+
const hashRoot = hashWorkspaceDirectory(rootDir, options);
|
|
851
|
+
if (Array.isArray(options?.workspaces)) {
|
|
852
|
+
return yield* Effect.all([
|
|
853
|
+
hashRoot,
|
|
854
|
+
...options.workspaces.map(({ cwd, ...options }) => hashWorkspaceDirectory(cwd, options)),
|
|
855
|
+
], { concurrency: "unbounded" }).pipe(Effect.flatMap(([root, ...workspaces]) => sha256Object([root, ...workspaces.sort()])), Effect.map((hash) => ({ hash, workspaces: undefined })));
|
|
856
|
+
}
|
|
857
|
+
const [root, workspaces] = yield* Effect.all([hashRoot, additionalWorkspaces], { concurrency: "unbounded" });
|
|
858
|
+
const workspaceHashes = yield* Effect.forEach(workspaces, (cwd) => hashWorkspaceDirectory(cwd), { concurrency: "unbounded" });
|
|
859
|
+
const hash = yield* sha256Object([root, ...workspaceHashes.sort()]);
|
|
860
|
+
return {
|
|
861
|
+
hash,
|
|
862
|
+
workspaces: Array.from(workspaces).map((cwd) => path.relative(rootDir, cwd)),
|
|
863
|
+
};
|
|
754
864
|
});
|
|
755
865
|
const prepareAssetsAndBundle = (id, props, opts = {}) => Effect.gen(function* () {
|
|
756
866
|
if (props.script !== undefined) {
|
|
@@ -766,24 +876,12 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
766
876
|
files: [{ path: "main.js", content: props.script }],
|
|
767
877
|
hash: bundleHash,
|
|
768
878
|
},
|
|
879
|
+
input: undefined,
|
|
880
|
+
additionalWorkspaces: undefined,
|
|
769
881
|
};
|
|
770
882
|
}
|
|
771
883
|
if (props.vite) {
|
|
772
|
-
|
|
773
|
-
viteBuild(props),
|
|
774
|
-
// hashDirectory expects `{ cwd, memo }`. The vite props
|
|
775
|
-
// store the project root under `rootDir`, so map it
|
|
776
|
-
// here. Without this, `cwd` falls back to
|
|
777
|
-
// `process.cwd()` and the input hash is computed over
|
|
778
|
-
// the wrong directory tree (often the entire monorepo
|
|
779
|
-
// root), making it both slow and unable to detect
|
|
780
|
-
// changes scoped to the actual Vite project.
|
|
781
|
-
hashDirectory({
|
|
782
|
-
cwd: props.vite.rootDir,
|
|
783
|
-
memo: props.vite.memo,
|
|
784
|
-
}),
|
|
785
|
-
], { concurrency: "unbounded" });
|
|
786
|
-
return { assets, bundle, input };
|
|
884
|
+
return yield* viteBuild(props);
|
|
787
885
|
}
|
|
788
886
|
const [assets, bundle] = yield* Effect.all([
|
|
789
887
|
opts.skipAssetsRead
|
|
@@ -791,8 +889,13 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
791
889
|
: prepareAssets(props.assets),
|
|
792
890
|
prepareBundle(id, props),
|
|
793
891
|
], { concurrency: "unbounded" });
|
|
794
|
-
return {
|
|
795
|
-
|
|
892
|
+
return {
|
|
893
|
+
assets,
|
|
894
|
+
bundle,
|
|
895
|
+
input: undefined,
|
|
896
|
+
additionalWorkspaces: undefined,
|
|
897
|
+
};
|
|
898
|
+
}).pipe(Effect.map(({ assets, bundle, input, additionalWorkspaces }) => ({
|
|
796
899
|
assets,
|
|
797
900
|
bundle: {
|
|
798
901
|
main: bundle?.files[0].path,
|
|
@@ -804,6 +907,7 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
804
907
|
assets: assets?.hash,
|
|
805
908
|
bundle: bundle?.hash,
|
|
806
909
|
input,
|
|
910
|
+
additionalWorkspaces,
|
|
807
911
|
},
|
|
808
912
|
})));
|
|
809
913
|
const normalizePrebuiltAssets = (assets, output) => {
|
|
@@ -847,7 +951,18 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
847
951
|
assets: prebuiltAssets?.hash ?? preparedHash.assets,
|
|
848
952
|
metadata: metadataHash,
|
|
849
953
|
};
|
|
850
|
-
|
|
954
|
+
// `transferredFrom` is alchemy-only transfer metadata on
|
|
955
|
+
// durable_object_namespace bindings — it drives the
|
|
956
|
+
// `transferred_classes` migration below and must be stripped from the
|
|
957
|
+
// wire-shape binding before upload.
|
|
958
|
+
const metadataBindings = bindings.flatMap((b) => (b.data.bindings ?? []).map((item) => {
|
|
959
|
+
if (item.type === "durable_object_namespace" &&
|
|
960
|
+
item.transferredFrom !== undefined) {
|
|
961
|
+
const { transferredFrom: _, ...rest } = item;
|
|
962
|
+
return rest;
|
|
963
|
+
}
|
|
964
|
+
return item;
|
|
965
|
+
}));
|
|
851
966
|
const expectedDurableObjectClassNames = getExpectedDurableObjectClassNames(metadataBindings, name);
|
|
852
967
|
let metadataAssets;
|
|
853
968
|
let keepAssets = false;
|
|
@@ -956,7 +1071,8 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
956
1071
|
.pipe(Effect.map((s) => s), Effect.catch(() => Effect.succeed(undefined))));
|
|
957
1072
|
const oldTags = Array.from(new Set(oldSettings?.tags ?? []));
|
|
958
1073
|
const oldBindings = oldSettings?.bindings ?? [];
|
|
959
|
-
// Parse
|
|
1074
|
+
// Parse the DO logical-id→class mapping from script tags (packed
|
|
1075
|
+
// `alchemy:dos:` and legacy per-DO `alchemy:do:` formats)
|
|
960
1076
|
const oldDoClassNameByLogicalId = getDurableObjectTagMap(oldTags);
|
|
961
1077
|
const currentDoBindings = getDurableObjectBindings(bindings, name);
|
|
962
1078
|
const currentDoClassNameByLogicalId = Object.fromEntries(currentDoBindings.map((binding) => [
|
|
@@ -968,11 +1084,13 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
968
1084
|
? [tag.slice("alchemy:migration-tag:".length)]
|
|
969
1085
|
: [])[0];
|
|
970
1086
|
const newMigrationTag = bumpMigrationTagVersion(oldMigrationTag);
|
|
971
|
-
// Compute
|
|
972
|
-
|
|
1087
|
+
// Compute delete-class candidates. Candidates are validated against
|
|
1088
|
+
// observed namespace ownership below — a class may already have been
|
|
1089
|
+
// transferred to another script by its new host's deploy.
|
|
1090
|
+
const deletedClassCandidates = [];
|
|
973
1091
|
for (const [logicalId, className] of Object.entries(oldDoClassNameByLogicalId)) {
|
|
974
1092
|
if (!currentDoClassNameByLogicalId[logicalId]) {
|
|
975
|
-
|
|
1093
|
+
deletedClassCandidates.push(className);
|
|
976
1094
|
}
|
|
977
1095
|
}
|
|
978
1096
|
// Backward compatibility for old workers that have DO bindings but no
|
|
@@ -988,36 +1106,150 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
988
1106
|
oldBinding.className &&
|
|
989
1107
|
ownedLocally &&
|
|
990
1108
|
!currentDoBindings.some((binding) => binding.bindingName === oldBinding.name)) {
|
|
991
|
-
|
|
1109
|
+
deletedClassCandidates.push(oldBinding.className);
|
|
992
1110
|
}
|
|
993
1111
|
}
|
|
994
1112
|
}
|
|
1113
|
+
// Class names the current deploy references *cross-script* (mapped to
|
|
1114
|
+
// the foreign script). A class that both leaves the "hosted here" set
|
|
1115
|
+
// and shows up here has moved to another Worker — Cloudflare rejects
|
|
1116
|
+
// deleting a class while any binding in the upload references its
|
|
1117
|
+
// class name, and deleting would destroy the namespace's data.
|
|
1118
|
+
const crossScriptClassTargets = new Map();
|
|
1119
|
+
for (const item of metadataBindings) {
|
|
1120
|
+
if (item.type === "durable_object_namespace" &&
|
|
1121
|
+
item.className &&
|
|
1122
|
+
typeof item.scriptName === "string" &&
|
|
1123
|
+
item.scriptName !== name) {
|
|
1124
|
+
crossScriptClassTargets.set(item.className, item.scriptName);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
// One account-level namespace listing serves both sides of a
|
|
1128
|
+
// transfer: the destination checks the source still hosts the class
|
|
1129
|
+
// before emitting `transferred_classes`, and the former host checks
|
|
1130
|
+
// whether a to-be-deleted class was already transferred away.
|
|
1131
|
+
// Dispatch-namespace user workers keep the legacy behavior — their
|
|
1132
|
+
// namespaces don't surface on the account-level list.
|
|
1133
|
+
const mayTransferIn = currentDoBindings.some((binding) => !oldDoClassNameByLogicalId[binding.logicalId] &&
|
|
1134
|
+
binding.transferredFrom !== undefined);
|
|
1135
|
+
const observedNamespaces = !dispatchNamespace &&
|
|
1136
|
+
(deletedClassCandidates.length > 0 || mayTransferIn)
|
|
1137
|
+
? yield* listDurableObjectNamespaces(accountId)
|
|
1138
|
+
: [];
|
|
1139
|
+
const hosts = (namespaces, scriptName, className) => namespaces.some((ns) => ns.script === scriptName && ns.class === className);
|
|
1140
|
+
const scriptHostsClass = (scriptName, className) => hosts(observedNamespaces, scriptName, className);
|
|
1141
|
+
const deletedClasses = [];
|
|
1142
|
+
for (const className of deletedClassCandidates) {
|
|
1143
|
+
if (dispatchNamespace) {
|
|
1144
|
+
deletedClasses.push(className);
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
const targetScriptName = crossScriptClassTargets.get(className);
|
|
1148
|
+
if (targetScriptName === undefined) {
|
|
1149
|
+
// Plain removal. Delete only if the namespace actually still
|
|
1150
|
+
// lives here — it may have been transferred to another script by
|
|
1151
|
+
// that script's deploy, or removed out-of-band. The stale
|
|
1152
|
+
// alchemy:do tag drops out either way because tags are recomputed
|
|
1153
|
+
// from current bindings.
|
|
1154
|
+
if (scriptHostsClass(name, className)) {
|
|
1155
|
+
deletedClasses.push(className);
|
|
1156
|
+
}
|
|
1157
|
+
continue;
|
|
1158
|
+
}
|
|
1159
|
+
// The class went local → cross-script. When the new host's deploy
|
|
1160
|
+
// ran a `transferred_classes` migration moments ago, the account
|
|
1161
|
+
// listing can briefly still attribute the namespace to this script,
|
|
1162
|
+
// so re-observe with a short bounded budget until the transfer
|
|
1163
|
+
// becomes visible (namespace off this script) or the state is
|
|
1164
|
+
// conclusively a conflict (still here — including the case where
|
|
1165
|
+
// the target created a *fresh* namespace for the same class name).
|
|
1166
|
+
const namespaces = yield* listDurableObjectNamespaces(accountId).pipe(Effect.repeat({
|
|
1167
|
+
schedule: Schedule.spaced("2 seconds"),
|
|
1168
|
+
until: (observed) => !hosts(observed, name, className) ||
|
|
1169
|
+
hosts(observed, targetScriptName, className),
|
|
1170
|
+
times: 5,
|
|
1171
|
+
}));
|
|
1172
|
+
if (!hosts(namespaces, name, className)) {
|
|
1173
|
+
// Transferred away — nothing to delete.
|
|
1174
|
+
continue;
|
|
1175
|
+
}
|
|
1176
|
+
// local → cross-script transition without a transfer. Fail before
|
|
1177
|
+
// any upload: Cloudflare would reject the combined delete + binding
|
|
1178
|
+
// anyway, and silently deleting would destroy the namespace's
|
|
1179
|
+
// data. See the error's docs for the two ways out
|
|
1180
|
+
// (`transferredFrom` on the new host, or a two-phase removal).
|
|
1181
|
+
return yield* Effect.fail(new DurableObjectTransferRequired({
|
|
1182
|
+
scriptName: name,
|
|
1183
|
+
className,
|
|
1184
|
+
targetScriptName,
|
|
1185
|
+
}));
|
|
1186
|
+
}
|
|
995
1187
|
// Collect container-backed class names so we can send container metadata
|
|
996
1188
|
const containerClassNames = new Set(bindings.flatMap((b) => (b.data.containers ?? []).map((c) => c.className)));
|
|
997
|
-
// Compute new and
|
|
1189
|
+
// Compute new, renamed, and transferred classes
|
|
998
1190
|
const newClasses = [];
|
|
999
1191
|
const newSqliteClasses = [];
|
|
1000
1192
|
const renamedClasses = [];
|
|
1193
|
+
const transferredClasses = [];
|
|
1001
1194
|
for (const binding of currentDoBindings) {
|
|
1002
1195
|
let previousClassName = oldDoClassNameByLogicalId[binding.logicalId];
|
|
1003
1196
|
if (!previousClassName) {
|
|
1004
|
-
// No
|
|
1197
|
+
// No DO metadata tag maps this logical id to a class — the
|
|
1005
1198
|
// worker was created outside Alchemy (raw API / Wrangler) or
|
|
1006
1199
|
// before these tags existed. Fall back to matching the observed
|
|
1007
1200
|
// cloud binding by binding name so adoption reuses the existing
|
|
1008
1201
|
// class instead of asking Cloudflare to create one that already
|
|
1009
1202
|
// exists (which fails the migration). This is the "first deploy
|
|
1010
1203
|
// must match the existing class name" path; once we write the
|
|
1011
|
-
// `alchemy:
|
|
1204
|
+
// `alchemy:dos:` tag, subsequent renames are driven by logical id.
|
|
1012
1205
|
const observed = oldBindings.find((old) => old.type === "durable_object_namespace" &&
|
|
1013
1206
|
"className" in old &&
|
|
1014
1207
|
old.className &&
|
|
1208
|
+
// Only a *locally-owned* binding proves the class exists on
|
|
1209
|
+
// this script. A cross-script binding under the same name —
|
|
1210
|
+
// e.g. this worker previously referenced another host's
|
|
1211
|
+
// class and now hosts its own — points at a foreign
|
|
1212
|
+
// namespace and must not suppress the create migration
|
|
1213
|
+
// (Cloudflare rejects a local binding for a class the
|
|
1214
|
+
// script isn't configured to implement).
|
|
1215
|
+
(!("scriptName" in old) ||
|
|
1216
|
+
old.scriptName === undefined ||
|
|
1217
|
+
old.scriptName === name) &&
|
|
1015
1218
|
old.name === binding.bindingName);
|
|
1016
1219
|
if (observed && "className" in observed && observed.className) {
|
|
1017
1220
|
previousClassName = observed.className;
|
|
1018
1221
|
}
|
|
1019
1222
|
}
|
|
1020
1223
|
if (!previousClassName) {
|
|
1224
|
+
// A class new to this script is a host move when the declaration
|
|
1225
|
+
// says so: `transferredFrom` lists the former host(s) — moves
|
|
1226
|
+
// are always declared, never inferred, because a class deleted
|
|
1227
|
+
// on one worker and created on another is otherwise ambiguous
|
|
1228
|
+
// between "move the data" and "delete + fresh namespace". The
|
|
1229
|
+
// declared source must be observed to still host the namespace;
|
|
1230
|
+
// otherwise (fresh stage, transfer already completed) fall
|
|
1231
|
+
// through to a plain create.
|
|
1232
|
+
const fromScript = dispatchNamespace
|
|
1233
|
+
? undefined
|
|
1234
|
+
: yield* resolveTransferSource({
|
|
1235
|
+
accountId,
|
|
1236
|
+
selfScriptName: name,
|
|
1237
|
+
logicalId: binding.logicalId,
|
|
1238
|
+
className: binding.className,
|
|
1239
|
+
sources: normalizeTransferSources(binding.transferredFrom, name),
|
|
1240
|
+
observedNamespaces,
|
|
1241
|
+
});
|
|
1242
|
+
if (fromScript !== undefined) {
|
|
1243
|
+
// Data-preserving move: ship Cloudflare's
|
|
1244
|
+
// `transferred_classes` migration instead of creating a
|
|
1245
|
+
// fresh class.
|
|
1246
|
+
transferredClasses.push({
|
|
1247
|
+
from: binding.className,
|
|
1248
|
+
fromScript,
|
|
1249
|
+
to: binding.className,
|
|
1250
|
+
});
|
|
1251
|
+
continue;
|
|
1252
|
+
}
|
|
1021
1253
|
// Default all new Durable Object classes to SQLite. Cloudflare
|
|
1022
1254
|
// recommends SQLite for new namespaces, and container-backed
|
|
1023
1255
|
// Durable Objects require it.
|
|
@@ -1035,28 +1267,29 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
1035
1267
|
currentDoClassNameByLogicalId,
|
|
1036
1268
|
deletedClasses,
|
|
1037
1269
|
renamedClasses,
|
|
1270
|
+
transferredClasses,
|
|
1038
1271
|
newSqliteClasses,
|
|
1039
1272
|
})}`);
|
|
1040
|
-
//
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
const metadataTags = Array.from(new Set([
|
|
1273
|
+
// Pack every DO logical-id→class mapping into as few `alchemy:dos:`
|
|
1274
|
+
// tags as possible — one tag per DO blows Cloudflare's 10-tag limit
|
|
1275
|
+
// at 7+ bindings (#811).
|
|
1276
|
+
const alchemyDoTags = encodeDurableObjectTags(currentDoBindings);
|
|
1277
|
+
const alchemyTags = [
|
|
1046
1278
|
...createAlchemyWorkerTags(id),
|
|
1047
1279
|
...alchemyDoTags,
|
|
1048
1280
|
...(newMigrationTag
|
|
1049
1281
|
? [`alchemy:migration-tag:${newMigrationTag}`]
|
|
1050
1282
|
: []),
|
|
1051
|
-
|
|
1052
|
-
]));
|
|
1283
|
+
];
|
|
1284
|
+
const metadataTags = Array.from(new Set([...alchemyTags, ...(news.tags ?? [])]));
|
|
1285
|
+
yield* validateWorkerTags(name, metadataTags, alchemyTags.length);
|
|
1053
1286
|
const migrations = {
|
|
1054
1287
|
oldTag: oldMigrationTag,
|
|
1055
1288
|
newTag: newMigrationTag,
|
|
1056
1289
|
newClasses,
|
|
1057
1290
|
deletedClasses,
|
|
1058
1291
|
renamedClasses,
|
|
1059
|
-
transferredClasses
|
|
1292
|
+
transferredClasses,
|
|
1060
1293
|
newSqliteClasses,
|
|
1061
1294
|
};
|
|
1062
1295
|
const metadataContainers = [...containerClassNames].map((className) => ({
|
|
@@ -1253,11 +1486,8 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
1253
1486
|
return assetsHash !== output.hash?.assets;
|
|
1254
1487
|
}
|
|
1255
1488
|
if (props.vite) {
|
|
1256
|
-
const
|
|
1257
|
-
|
|
1258
|
-
memo: props.vite.memo,
|
|
1259
|
-
});
|
|
1260
|
-
return input !== output.hash?.input;
|
|
1489
|
+
const { hash } = yield* hashViteInput(props.vite.rootDir, props.vite.memo, Effect.succeed(output.hash?.additionalWorkspaces ?? []));
|
|
1490
|
+
return hash !== output.hash?.input;
|
|
1261
1491
|
}
|
|
1262
1492
|
const bundleHash = yield* prepareBundle(id, props).pipe(Effect.map((b) => b.hash));
|
|
1263
1493
|
if (bundleHash !== output.hash?.bundle) {
|
|
@@ -1489,19 +1719,27 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
1489
1719
|
const exportDerived = Object.keys(exportMap)
|
|
1490
1720
|
.filter((logicalId) => isDurableObjectExport(exportMap[logicalId]))
|
|
1491
1721
|
.map((logicalId) => ({ logicalId, className: logicalId }));
|
|
1492
|
-
|
|
1722
|
+
// Transfer-destination classes are excluded from the placeholder
|
|
1723
|
+
// entirely (class list, bindings, tags): Cloudflare forbids
|
|
1724
|
+
// creating the destination class of a `transferred_classes`
|
|
1725
|
+
// migration ahead of the transfer, so `reconcile` must perform it
|
|
1726
|
+
// with the real upload. (`transferredFrom` may still be an
|
|
1727
|
+
// unresolved Output here — precreate runs on raw props — but only
|
|
1728
|
+
// its presence matters.)
|
|
1729
|
+
const durableObjects = mergeDurableObjectClasses(exportDerived, getDurableObjectBindings(bindings, name)).filter((binding) => !binding.transferredFrom);
|
|
1493
1730
|
const doClasses = durableObjects.map((binding) => binding.className);
|
|
1494
1731
|
// Only attach container metadata for classes actually fronted by a
|
|
1495
1732
|
// Container binding (mirrors reconcile's `containerClassNames`).
|
|
1496
1733
|
// Mapping every DO class to a container would wrongly mark plain DOs
|
|
1497
1734
|
// as container-backed in the placeholder.
|
|
1498
1735
|
const containers = Array.from(new Set(bindings.flatMap((b) => (b.data.containers ?? []).map((c) => c.className)))).map((className) => ({ className }));
|
|
1499
|
-
const alchemyDoTags = durableObjects
|
|
1500
|
-
const
|
|
1736
|
+
const alchemyDoTags = encodeDurableObjectTags(durableObjects);
|
|
1737
|
+
const alchemyTags = [
|
|
1501
1738
|
...createAlchemyWorkerTags(id),
|
|
1502
1739
|
...alchemyDoTags,
|
|
1503
|
-
|
|
1504
|
-
]));
|
|
1740
|
+
];
|
|
1741
|
+
const tags = Array.from(new Set([...alchemyTags, ...(news.tags ?? [])]));
|
|
1742
|
+
yield* validateWorkerTags(name, tags, alchemyTags.length);
|
|
1505
1743
|
yield* Effect.logInfo(`Cloudflare Worker precreate: starting ${name}`);
|
|
1506
1744
|
yield* Effect.logInfo(`Cloudflare Worker precreate: durable objects ${JSON.stringify(durableObjects)}`);
|
|
1507
1745
|
const existingSettings = yield* getScriptSettings(accountId, name, dispatchNamespace).pipe(
|
|
@@ -1729,8 +1967,8 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
1729
1967
|
// The dispatch-namespace endpoints raise
|
|
1730
1968
|
// `DispatchNamespaceScriptNotFound` / `DispatchNamespaceNotFound`.
|
|
1731
1969
|
Effect.catchTag("WorkerNotFound", () => Effect.succeed(undefined)), Effect.catchTag("WorkerHasNoVersions", () => Effect.succeed(undefined)), Effect.catchTag("DispatchNamespaceScriptNotFound", () => Effect.succeed(undefined)), Effect.catchTag("DispatchNamespaceNotFound", () => Effect.succeed(undefined)));
|
|
1732
|
-
yield* Effect.logInfo(`Cloudflare Worker reconcile: existing durable object tags ${JSON.stringify((existingSettings?.tags ?? []).filter(
|
|
1733
|
-
yield* Effect.logInfo(`Cloudflare Worker reconcile: previous durable object tags ${JSON.stringify((output?.tags ?? []).filter(
|
|
1970
|
+
yield* Effect.logInfo(`Cloudflare Worker reconcile: existing durable object tags ${JSON.stringify((existingSettings?.tags ?? []).filter(isDurableObjectTag))}`);
|
|
1971
|
+
yield* Effect.logInfo(`Cloudflare Worker reconcile: previous durable object tags ${JSON.stringify((output?.tags ?? []).filter(isDurableObjectTag))}`);
|
|
1734
1972
|
return yield* putWorker(id, news, bindings, olds, output, session, existingSettings);
|
|
1735
1973
|
}),
|
|
1736
1974
|
delete: Effect.fn(function* ({ output }) {
|
|
@@ -1819,6 +2057,26 @@ const contentTypeFromExtension = (extension) => {
|
|
|
1819
2057
|
return "application/octet-stream";
|
|
1820
2058
|
}
|
|
1821
2059
|
};
|
|
2060
|
+
/**
|
|
2061
|
+
* Observe every Durable Object namespace on the account as `(script, class)`
|
|
2062
|
+
* pairs. Namespace ownership is authoritative cloud state: after a
|
|
2063
|
+
* `transferred_classes` migration the namespace moves to the receiving
|
|
2064
|
+
* script, so this is how both sides of a transfer observe where a class
|
|
2065
|
+
* currently lives — the destination checks the source still hosts the class
|
|
2066
|
+
* before emitting the transfer, and the former host checks whether a class
|
|
2067
|
+
* it is about to delete has already been transferred away.
|
|
2068
|
+
*/
|
|
2069
|
+
const listDurableObjectNamespaces = (accountId) => durableObjectsApi.listNamespaces.items({ accountId }).pipe(Stream.runCollect, Effect.map((namespaces) => Array.from(namespaces).flatMap((ns) => ns.script && ns.class ? [{ script: ns.script, class: ns.class }] : [])));
|
|
2070
|
+
/**
|
|
2071
|
+
* Coerce a resolved `transferredFrom` declaration to its list form, dropping
|
|
2072
|
+
* self-references (a worker naming itself as its own former host is
|
|
2073
|
+
* meaningless — the class already lives there).
|
|
2074
|
+
*/
|
|
2075
|
+
const normalizeTransferSources = (value, selfScriptName) => (value === undefined
|
|
2076
|
+
? []
|
|
2077
|
+
: Array.isArray(value)
|
|
2078
|
+
? value
|
|
2079
|
+
: [value]).filter((source) => source !== selfScriptName);
|
|
1822
2080
|
function bumpMigrationTagVersion(oldTag) {
|
|
1823
2081
|
if (!oldTag)
|
|
1824
2082
|
return undefined;
|
|
@@ -1830,7 +2088,7 @@ function bumpMigrationTagVersion(oldTag) {
|
|
|
1830
2088
|
/**
|
|
1831
2089
|
* Merges a worker's export-derived and binding-derived Durable Object class
|
|
1832
2090
|
* lists for the precreate placeholder, deduping by class name. The
|
|
1833
|
-
* binding-derived entry wins on a collision so the `alchemy:
|
|
2091
|
+
* binding-derived entry wins on a collision so the `alchemy:dos:` tag keys off
|
|
1834
2092
|
* the same logical id (the binding sid) that `reconcile` writes.
|
|
1835
2093
|
*/
|
|
1836
2094
|
function mergeDurableObjectClasses(exportDerived, bindingDerived) {
|
|
@@ -1864,19 +2122,150 @@ function getDurableObjectBindings(bindings, workerName) {
|
|
|
1864
2122
|
logicalId: binding.sid,
|
|
1865
2123
|
bindingName: item.name,
|
|
1866
2124
|
className: item.className,
|
|
2125
|
+
// Declared host history for a data-preserving
|
|
2126
|
+
// `transferred_classes` migration. Normalize an empty list to
|
|
2127
|
+
// "not declared"; self-references are dropped at resolution time.
|
|
2128
|
+
transferredFrom: Array.isArray(item.transferredFrom) &&
|
|
2129
|
+
item.transferredFrom.length === 0
|
|
2130
|
+
? undefined
|
|
2131
|
+
: item.transferredFrom,
|
|
1867
2132
|
},
|
|
1868
2133
|
];
|
|
1869
2134
|
}));
|
|
1870
2135
|
}
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
2136
|
+
/**
|
|
2137
|
+
* Cloudflare Worker script-tag limits, verified empirically against the live
|
|
2138
|
+
* API (2026-07):
|
|
2139
|
+
*
|
|
2140
|
+
* - at most **10 tags** per Worker (the 11th is rejected with `Forbidden`)
|
|
2141
|
+
* - each tag is at most **1024 bytes** (`BadRequest: Tag is too large`)
|
|
2142
|
+
* - tags may not contain `,` or `&`; everything else (`:`, `;`, `=`, `/`,
|
|
2143
|
+
* spaces, unicode) is accepted and round-trips intact
|
|
2144
|
+
*
|
|
2145
|
+
* Alchemy reserves 3 ownership tags (`alchemy:stack/stage/id`) and 1
|
|
2146
|
+
* migration tag, so the Durable Object logical-id→class mapping must not
|
|
2147
|
+
* spend one tag per DO (#811). Instead all mappings are packed into as few
|
|
2148
|
+
* `alchemy:dos:` tags as possible.
|
|
2149
|
+
*/
|
|
2150
|
+
const MAX_TAGS_PER_WORKER = 10;
|
|
2151
|
+
const MAX_TAG_BYTES = 1024;
|
|
2152
|
+
const LEGACY_DO_TAG_PREFIX = "alchemy:do:";
|
|
2153
|
+
const PACKED_DO_TAG_PREFIX = "alchemy:dos:";
|
|
2154
|
+
class InvalidWorkerTags extends Data.TaggedError("InvalidWorkerTags") {
|
|
2155
|
+
}
|
|
2156
|
+
/**
|
|
2157
|
+
* Pack Durable Object logical-id→class mappings into `alchemy:dos:` tags.
|
|
2158
|
+
*
|
|
2159
|
+
* Each mapping is encoded as `logicalId=className` — elided to just
|
|
2160
|
+
* `className` when the two are equal (the common case for export-derived
|
|
2161
|
+
* classes) — with both components `encodeURIComponent`-escaped so the `;`
|
|
2162
|
+
* pair separator, the `=` delimiter, and Cloudflare's forbidden tag
|
|
2163
|
+
* characters (`,`, `&`) can never collide with user identifiers. Pairs are
|
|
2164
|
+
* sorted for deterministic output and greedily packed so each tag stays
|
|
2165
|
+
* within Cloudflare's 1024-byte tag limit; workers with more DOs than fit in
|
|
2166
|
+
* one tag spill into additional `alchemy:dos:` tags.
|
|
2167
|
+
*
|
|
2168
|
+
* `encodeURIComponent` output is pure ASCII, so `String.length` equals the
|
|
2169
|
+
* tag's byte length.
|
|
2170
|
+
*
|
|
2171
|
+
* @internal exported for unit testing.
|
|
2172
|
+
*/
|
|
2173
|
+
export function encodeDurableObjectTags(durableObjects) {
|
|
2174
|
+
const pairs = [...durableObjects]
|
|
2175
|
+
.sort((a, b) => a.logicalId.localeCompare(b.logicalId))
|
|
2176
|
+
.map(({ logicalId, className }) => logicalId === className
|
|
2177
|
+
? encodeURIComponent(className)
|
|
2178
|
+
: `${encodeURIComponent(logicalId)}=${encodeURIComponent(className)}`);
|
|
2179
|
+
const tags = [];
|
|
2180
|
+
let payload = "";
|
|
2181
|
+
for (const pair of pairs) {
|
|
2182
|
+
const appended = payload === "" ? pair : `${payload};${pair}`;
|
|
2183
|
+
if (PACKED_DO_TAG_PREFIX.length + appended.length > MAX_TAG_BYTES &&
|
|
2184
|
+
payload !== "") {
|
|
2185
|
+
tags.push(`${PACKED_DO_TAG_PREFIX}${payload}`);
|
|
2186
|
+
payload = pair;
|
|
1875
2187
|
}
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
2188
|
+
else {
|
|
2189
|
+
payload = appended;
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
if (payload !== "") {
|
|
2193
|
+
tags.push(`${PACKED_DO_TAG_PREFIX}${payload}`);
|
|
2194
|
+
}
|
|
2195
|
+
return tags;
|
|
1881
2196
|
}
|
|
2197
|
+
/**
|
|
2198
|
+
* Parse the Durable Object logical-id→class mapping from a worker's script
|
|
2199
|
+
* tags. Reads both formats so workers deployed before the packed format roll
|
|
2200
|
+
* forward transparently:
|
|
2201
|
+
*
|
|
2202
|
+
* - legacy: one `alchemy:do:{logicalId}:{className}` tag per DO
|
|
2203
|
+
* - packed: `alchemy:dos:{pair};{pair};…` (see {@link encodeDurableObjectTags})
|
|
2204
|
+
*
|
|
2205
|
+
* A packed entry wins over a legacy entry for the same logical id.
|
|
2206
|
+
*
|
|
2207
|
+
* @internal exported for unit testing.
|
|
2208
|
+
*/
|
|
2209
|
+
export function getDurableObjectTagMap(tags) {
|
|
2210
|
+
const map = {};
|
|
2211
|
+
for (const tag of tags) {
|
|
2212
|
+
if (tag.startsWith(LEGACY_DO_TAG_PREFIX)) {
|
|
2213
|
+
const parts = tag.split(":");
|
|
2214
|
+
const logicalId = parts[2];
|
|
2215
|
+
const className = parts.slice(3).join(":");
|
|
2216
|
+
if (logicalId && className && !(logicalId in map)) {
|
|
2217
|
+
map[logicalId] = className;
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
for (const tag of tags) {
|
|
2222
|
+
if (tag.startsWith(PACKED_DO_TAG_PREFIX)) {
|
|
2223
|
+
for (const pair of tag.slice(PACKED_DO_TAG_PREFIX.length).split(";")) {
|
|
2224
|
+
if (pair === "")
|
|
2225
|
+
continue;
|
|
2226
|
+
const eq = pair.indexOf("=");
|
|
2227
|
+
const logicalId = decodeURIComponent(eq === -1 ? pair : pair.slice(0, eq));
|
|
2228
|
+
const className = decodeURIComponent(eq === -1 ? pair : pair.slice(eq + 1));
|
|
2229
|
+
if (logicalId && className) {
|
|
2230
|
+
map[logicalId] = className;
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
return map;
|
|
2236
|
+
}
|
|
2237
|
+
const isDurableObjectTag = (tag) => tag.startsWith(LEGACY_DO_TAG_PREFIX) || tag.startsWith(PACKED_DO_TAG_PREFIX);
|
|
2238
|
+
/**
|
|
2239
|
+
* Fail fast — before the script upload — when a worker's tag set violates
|
|
2240
|
+
* Cloudflare's limits, instead of surfacing the raw `Forbidden`/`BadRequest`
|
|
2241
|
+
* at PUT time (#811). `alchemyTagCount` is the number of tags alchemy itself
|
|
2242
|
+
* generated (ownership + migration + packed DO tags) so the message can tell
|
|
2243
|
+
* the user how much of the budget is theirs.
|
|
2244
|
+
*/
|
|
2245
|
+
const validateWorkerTags = (scriptName, tags, alchemyTagCount) => Effect.gen(function* () {
|
|
2246
|
+
if (tags.length > MAX_TAGS_PER_WORKER) {
|
|
2247
|
+
return yield* Effect.fail(new InvalidWorkerTags({
|
|
2248
|
+
scriptName,
|
|
2249
|
+
reason: `worker "${scriptName}" needs ${tags.length} script tags but Cloudflare allows at most ${MAX_TAGS_PER_WORKER}. ` +
|
|
2250
|
+
`Alchemy reserves ${alchemyTagCount} (ownership, migration and durable-object metadata); ` +
|
|
2251
|
+
`${tags.length - alchemyTagCount} user tags were passed via \`tags\`. Remove ${tags.length - MAX_TAGS_PER_WORKER} tag(s).`,
|
|
2252
|
+
}));
|
|
2253
|
+
}
|
|
2254
|
+
const encoder = new TextEncoder();
|
|
2255
|
+
for (const tag of tags) {
|
|
2256
|
+
if (tag.includes(",") || tag.includes("&")) {
|
|
2257
|
+
return yield* Effect.fail(new InvalidWorkerTags({
|
|
2258
|
+
scriptName,
|
|
2259
|
+
reason: `worker "${scriptName}" tag ${JSON.stringify(tag)} contains ',' or '&', which Cloudflare rejects.`,
|
|
2260
|
+
}));
|
|
2261
|
+
}
|
|
2262
|
+
const bytes = yield* Effect.sync(() => encoder.encode(tag).length);
|
|
2263
|
+
if (bytes > MAX_TAG_BYTES) {
|
|
2264
|
+
return yield* Effect.fail(new InvalidWorkerTags({
|
|
2265
|
+
scriptName,
|
|
2266
|
+
reason: `worker "${scriptName}" tag ${JSON.stringify(tag.slice(0, 64))}… is ${bytes} bytes; Cloudflare allows at most ${MAX_TAG_BYTES}.`,
|
|
2267
|
+
}));
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
});
|
|
1882
2271
|
//# sourceMappingURL=WorkerProvider.js.map
|