alchemy 2.0.0-beta.43 → 2.0.0-beta.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +18 -5
- package/bin/exec.js +381 -240
- package/bin/exec.js.map +1 -1
- package/lib/AWS/Lambda/Function.d.ts +17 -0
- package/lib/AWS/Lambda/Function.d.ts.map +1 -1
- package/lib/AWS/Lambda/Function.js +61 -16
- package/lib/AWS/Lambda/Function.js.map +1 -1
- package/lib/AWS/Providers.d.ts +2 -1
- package/lib/AWS/Providers.d.ts.map +1 -1
- package/lib/AWS/Providers.js +3 -1
- package/lib/AWS/Providers.js.map +1 -1
- package/lib/Apply.js +17 -1
- package/lib/Apply.js.map +1 -1
- package/lib/Auth/AuthProvider.d.ts.map +1 -1
- package/lib/Auth/AuthProvider.js +24 -6
- package/lib/Auth/AuthProvider.js.map +1 -1
- package/lib/Auth/Credentials.d.ts.map +1 -1
- package/lib/Auth/Credentials.js +3 -3
- package/lib/Auth/Credentials.js.map +1 -1
- package/lib/Auth/Lock.js +2 -2
- package/lib/Auth/Lock.js.map +1 -1
- package/lib/Bundle/Bundle.d.ts +11 -0
- package/lib/Bundle/Bundle.d.ts.map +1 -1
- package/lib/Bundle/Bundle.js +19 -12
- package/lib/Bundle/Bundle.js.map +1 -1
- package/lib/Bundle/BundleAnalyzerPlugin.d.ts +25 -0
- package/lib/Bundle/BundleAnalyzerPlugin.d.ts.map +1 -0
- package/lib/Bundle/BundleAnalyzerPlugin.js +16 -0
- package/lib/Bundle/BundleAnalyzerPlugin.js.map +1 -0
- package/lib/Bundle/RawPlugin.d.ts +36 -0
- package/lib/Bundle/RawPlugin.d.ts.map +1 -0
- package/lib/Bundle/RawPlugin.js +80 -0
- package/lib/Bundle/RawPlugin.js.map +1 -0
- package/lib/Bundle/index.d.ts +2 -0
- package/lib/Bundle/index.d.ts.map +1 -1
- package/lib/Bundle/index.js +2 -0
- package/lib/Bundle/index.js.map +1 -1
- package/lib/Cli/commands/_shared.d.ts +13 -1
- package/lib/Cli/commands/_shared.d.ts.map +1 -1
- package/lib/Cli/commands/_shared.js +33 -2
- package/lib/Cli/commands/_shared.js.map +1 -1
- package/lib/Cli/commands/dev.d.ts +3 -2
- package/lib/Cli/commands/dev.d.ts.map +1 -1
- package/lib/Cli/commands/dev.js +19 -2
- package/lib/Cli/commands/dev.js.map +1 -1
- package/lib/Cli/commands/login.d.ts.map +1 -1
- package/lib/Cli/commands/login.js +19 -5
- 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 -27
- package/lib/Cli/commands/profile.js.map +1 -1
- package/lib/Cli/exec.d.ts.map +1 -1
- package/lib/Cli/exec.js +2 -1
- package/lib/Cli/exec.js.map +1 -1
- package/lib/Cli/main.d.ts.map +1 -1
- package/lib/Cli/main.js +0 -2
- package/lib/Cli/main.js.map +1 -1
- package/lib/Cloudflare/AiGateway/AiGateway.d.ts +0 -2
- package/lib/Cloudflare/AiGateway/AiGateway.d.ts.map +1 -1
- package/lib/Cloudflare/AiGateway/AiGateway.js +2 -4
- package/lib/Cloudflare/AiGateway/AiGateway.js.map +1 -1
- package/lib/Cloudflare/BrowserRendering/BrowserRendering.d.ts +116 -0
- package/lib/Cloudflare/BrowserRendering/BrowserRendering.d.ts.map +1 -0
- package/lib/Cloudflare/BrowserRendering/BrowserRendering.js +92 -0
- package/lib/Cloudflare/BrowserRendering/BrowserRendering.js.map +1 -0
- package/lib/Cloudflare/BrowserRendering/BrowserRenderingBinding.d.ts +55 -0
- package/lib/Cloudflare/BrowserRendering/BrowserRenderingBinding.d.ts.map +1 -0
- package/lib/Cloudflare/BrowserRendering/BrowserRenderingBinding.js +55 -0
- package/lib/Cloudflare/BrowserRendering/BrowserRenderingBinding.js.map +1 -0
- package/lib/Cloudflare/BrowserRendering/index.d.ts +3 -0
- package/lib/Cloudflare/BrowserRendering/index.d.ts.map +1 -0
- package/lib/Cloudflare/BrowserRendering/index.js +3 -0
- package/lib/Cloudflare/BrowserRendering/index.js.map +1 -0
- package/lib/Cloudflare/Container/Container.d.ts +3 -3
- package/lib/Cloudflare/Container/Container.js +3 -3
- package/lib/Cloudflare/Container/StartContainer.d.ts.map +1 -1
- package/lib/Cloudflare/Container/StartContainer.js.map +1 -1
- package/lib/Cloudflare/D1/D1Database.d.ts +1 -0
- package/lib/Cloudflare/D1/D1Database.d.ts.map +1 -1
- package/lib/Cloudflare/D1/D1Database.js +2 -1
- package/lib/Cloudflare/D1/D1Database.js.map +1 -1
- package/lib/Cloudflare/D1/D1DatabaseBinding.js +1 -1
- package/lib/Cloudflare/D1/D1DatabaseBinding.js.map +1 -1
- package/lib/Cloudflare/Fetcher.d.ts.map +1 -1
- package/lib/Cloudflare/Fetcher.js +0 -2
- package/lib/Cloudflare/Fetcher.js.map +1 -1
- package/lib/Cloudflare/Hyperdrive/Hyperdrive.d.ts +1 -0
- package/lib/Cloudflare/Hyperdrive/Hyperdrive.d.ts.map +1 -1
- package/lib/Cloudflare/Hyperdrive/Hyperdrive.js +3 -0
- package/lib/Cloudflare/Hyperdrive/Hyperdrive.js.map +1 -1
- package/lib/Cloudflare/Hyperdrive/HyperdriveBinding.d.ts +3 -2
- package/lib/Cloudflare/Hyperdrive/HyperdriveBinding.d.ts.map +1 -1
- package/lib/Cloudflare/Hyperdrive/HyperdriveBinding.js +32 -33
- package/lib/Cloudflare/Hyperdrive/HyperdriveBinding.js.map +1 -1
- package/lib/Cloudflare/KV/KVNamespace.d.ts +1 -0
- package/lib/Cloudflare/KV/KVNamespace.d.ts.map +1 -1
- package/lib/Cloudflare/KV/KVNamespace.js +2 -0
- package/lib/Cloudflare/KV/KVNamespace.js.map +1 -1
- package/lib/Cloudflare/Local.d.ts +2 -0
- package/lib/Cloudflare/Local.d.ts.map +1 -0
- package/lib/Cloudflare/Local.js +9 -0
- package/lib/Cloudflare/Local.js.map +1 -0
- package/lib/Cloudflare/Providers.d.ts +2 -1
- package/lib/Cloudflare/Providers.d.ts.map +1 -1
- package/lib/Cloudflare/Providers.js +23 -17
- package/lib/Cloudflare/Providers.js.map +1 -1
- package/lib/Cloudflare/Queue/Queue.d.ts +1 -0
- package/lib/Cloudflare/Queue/Queue.d.ts.map +1 -1
- package/lib/Cloudflare/Queue/Queue.js +1 -0
- package/lib/Cloudflare/Queue/Queue.js.map +1 -1
- package/lib/Cloudflare/Queue/QueueConsumer.d.ts +2 -1
- package/lib/Cloudflare/Queue/QueueConsumer.d.ts.map +1 -1
- package/lib/Cloudflare/Queue/QueueConsumer.js +11 -3
- package/lib/Cloudflare/Queue/QueueConsumer.js.map +1 -1
- package/lib/Cloudflare/Queue/QueueEventSource.d.ts +30 -4
- package/lib/Cloudflare/Queue/QueueEventSource.d.ts.map +1 -1
- package/lib/Cloudflare/Queue/QueueEventSource.js +22 -1
- package/lib/Cloudflare/Queue/QueueEventSource.js.map +1 -1
- package/lib/Cloudflare/R2/R2Bucket.d.ts +1 -0
- package/lib/Cloudflare/R2/R2Bucket.d.ts.map +1 -1
- package/lib/Cloudflare/R2/R2Bucket.js +18 -0
- package/lib/Cloudflare/R2/R2Bucket.js.map +1 -1
- package/lib/Cloudflare/SecretsStore/Secret.d.ts.map +1 -1
- package/lib/Cloudflare/SecretsStore/Secret.js +13 -34
- package/lib/Cloudflare/SecretsStore/Secret.js.map +1 -1
- package/lib/Cloudflare/SecretsStore/SecretBinding.d.ts +3 -2
- package/lib/Cloudflare/SecretsStore/SecretBinding.d.ts.map +1 -1
- package/lib/Cloudflare/SecretsStore/SecretBinding.js +3 -2
- package/lib/Cloudflare/SecretsStore/SecretBinding.js.map +1 -1
- package/lib/Cloudflare/StateStore/Api.d.ts +5 -13
- package/lib/Cloudflare/StateStore/Api.d.ts.map +1 -1
- package/lib/Cloudflare/StateStore/Api.js +14 -8
- package/lib/Cloudflare/StateStore/Api.js.map +1 -1
- package/lib/Cloudflare/StateStore/State.d.ts.map +1 -1
- package/lib/Cloudflare/StateStore/State.js +45 -9
- package/lib/Cloudflare/StateStore/State.js.map +1 -1
- package/lib/Cloudflare/StateStore/Store.d.ts.map +1 -1
- package/lib/Cloudflare/StateStore/Store.js +5 -2
- package/lib/Cloudflare/StateStore/Store.js.map +1 -1
- package/lib/Cloudflare/VpcService/VpcService.d.ts +2 -2
- package/lib/Cloudflare/VpcService/VpcService.d.ts.map +1 -1
- package/lib/Cloudflare/Website/StaticSite.d.ts +5 -5
- package/lib/Cloudflare/Website/StaticSite.d.ts.map +1 -1
- package/lib/Cloudflare/Website/StaticSite.js +3 -0
- package/lib/Cloudflare/Website/StaticSite.js.map +1 -1
- package/lib/Cloudflare/Website/Vite.d.ts +5 -5
- package/lib/Cloudflare/Website/Vite.d.ts.map +1 -1
- package/lib/Cloudflare/Website/Vite.js.map +1 -1
- package/lib/Cloudflare/Workers/Assets.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Assets.js +1 -1
- package/lib/Cloudflare/Workers/Assets.js.map +1 -1
- package/lib/Cloudflare/Workers/DurableObjectBridge.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/DurableObjectBridge.js +4 -3
- package/lib/Cloudflare/Workers/DurableObjectBridge.js.map +1 -1
- package/lib/Cloudflare/Workers/DurableObjectNamespace.d.ts +183 -6
- package/lib/Cloudflare/Workers/DurableObjectNamespace.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/DurableObjectNamespace.js +279 -76
- package/lib/Cloudflare/Workers/DurableObjectNamespace.js.map +1 -1
- package/lib/Cloudflare/Workers/HttpServer.d.ts +6 -4
- package/lib/Cloudflare/Workers/HttpServer.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/HttpServer.js +20 -15
- package/lib/Cloudflare/Workers/HttpServer.js.map +1 -1
- package/lib/Cloudflare/Workers/InferEnv.d.ts +3 -2
- package/lib/Cloudflare/Workers/InferEnv.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts +19 -3
- package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js +458 -21
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js.map +1 -1
- package/lib/Cloudflare/Workers/Rpc.d.ts +16 -0
- package/lib/Cloudflare/Workers/Rpc.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Rpc.js +22 -0
- package/lib/Cloudflare/Workers/Rpc.js.map +1 -1
- package/lib/Cloudflare/Workers/RpcDurableObjectNamespace.d.ts +285 -0
- package/lib/Cloudflare/Workers/RpcDurableObjectNamespace.d.ts.map +1 -0
- package/lib/Cloudflare/Workers/RpcDurableObjectNamespace.js +288 -0
- package/lib/Cloudflare/Workers/RpcDurableObjectNamespace.js.map +1 -0
- package/lib/Cloudflare/Workers/RpcWorker.d.ts +305 -0
- package/lib/Cloudflare/Workers/RpcWorker.d.ts.map +1 -0
- package/lib/Cloudflare/Workers/RpcWorker.js +350 -0
- package/lib/Cloudflare/Workers/RpcWorker.js.map +1 -0
- package/lib/Cloudflare/Workers/Vite.d.ts +1 -1
- package/lib/Cloudflare/Workers/Vite.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Vite.js +2 -1
- package/lib/Cloudflare/Workers/Vite.js.map +1 -1
- package/lib/Cloudflare/Workers/Worker.d.ts +69 -37
- package/lib/Cloudflare/Workers/Worker.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Worker.js +171 -51
- package/lib/Cloudflare/Workers/Worker.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerAsyncBindings.d.ts +1 -1
- package/lib/Cloudflare/Workers/WorkerAsyncBindings.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerAsyncBindings.js +158 -97
- package/lib/Cloudflare/Workers/WorkerAsyncBindings.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBinding.d.ts +11 -23
- package/lib/Cloudflare/Workers/WorkerBinding.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBinding.js +3 -0
- 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 +8 -7
- package/lib/Cloudflare/Workers/WorkerBridge.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBundle.d.ts +1 -2
- package/lib/Cloudflare/Workers/WorkerBundle.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBundle.js +7 -7
- package/lib/Cloudflare/Workers/WorkerBundle.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerRuntimeContext.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerRuntimeContext.js +9 -10
- package/lib/Cloudflare/Workers/WorkerRuntimeContext.js.map +1 -1
- package/lib/Cloudflare/Workers/Workflow.d.ts +5 -3
- package/lib/Cloudflare/Workers/Workflow.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Workflow.js +19 -1
- package/lib/Cloudflare/Workers/Workflow.js.map +1 -1
- package/lib/Cloudflare/Workers/index.d.ts +2 -0
- package/lib/Cloudflare/Workers/index.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/index.js +2 -0
- package/lib/Cloudflare/Workers/index.js.map +1 -1
- package/lib/Cloudflare/Zaraz/ZarazConfig.d.ts +184 -0
- package/lib/Cloudflare/Zaraz/ZarazConfig.d.ts.map +1 -0
- package/lib/Cloudflare/Zaraz/ZarazConfig.js +216 -0
- package/lib/Cloudflare/Zaraz/ZarazConfig.js.map +1 -0
- package/lib/Cloudflare/Zaraz/ZarazEventTypes.d.ts +188 -0
- package/lib/Cloudflare/Zaraz/ZarazEventTypes.d.ts.map +1 -0
- package/lib/Cloudflare/Zaraz/ZarazEventTypes.js +4 -0
- package/lib/Cloudflare/Zaraz/ZarazEventTypes.js.map +1 -0
- package/lib/Cloudflare/Zaraz/index.d.ts +3 -0
- package/lib/Cloudflare/Zaraz/index.d.ts.map +1 -0
- package/lib/Cloudflare/Zaraz/index.js +2 -0
- package/lib/Cloudflare/Zaraz/index.js.map +1 -0
- package/lib/Cloudflare/index.d.ts +2 -0
- package/lib/Cloudflare/index.d.ts.map +1 -1
- package/lib/Cloudflare/index.js +2 -0
- package/lib/Cloudflare/index.js.map +1 -1
- package/lib/Dependencies.d.ts +10 -0
- package/lib/Dependencies.d.ts.map +1 -0
- package/lib/Dependencies.js +1 -0
- package/lib/Dependencies.js.map +1 -0
- package/lib/Deploy.d.ts +2 -1
- package/lib/Deploy.d.ts.map +1 -1
- package/lib/Deploy.js +2 -2
- package/lib/Deploy.js.map +1 -1
- package/lib/Diff.d.ts +11 -0
- package/lib/Diff.d.ts.map +1 -1
- package/lib/Diff.js +11 -0
- package/lib/Diff.js.map +1 -1
- package/lib/Input.d.ts +2 -1
- package/lib/Input.d.ts.map +1 -1
- package/lib/KeyPair.d.ts +77 -0
- package/lib/KeyPair.d.ts.map +1 -0
- package/lib/KeyPair.js +102 -0
- package/lib/KeyPair.js.map +1 -0
- package/lib/Local/RpcProvider.d.ts +56 -0
- package/lib/Local/RpcProvider.d.ts.map +1 -0
- package/lib/Local/RpcProvider.js +83 -0
- package/lib/Local/RpcProvider.js.map +1 -0
- package/lib/Local/RpcProviderProxy.d.ts +19 -0
- package/lib/Local/RpcProviderProxy.d.ts.map +1 -0
- package/lib/Local/RpcProviderProxy.js +48 -0
- package/lib/Local/RpcProviderProxy.js.map +1 -0
- package/lib/Local/RpcSerialization.d.ts +34 -0
- package/lib/Local/RpcSerialization.d.ts.map +1 -0
- package/lib/Local/RpcSerialization.js +120 -0
- package/lib/Local/RpcSerialization.js.map +1 -0
- package/lib/Local/RpcServer.d.ts +63 -0
- package/lib/Local/RpcServer.d.ts.map +1 -0
- package/lib/Local/RpcServer.js +72 -0
- package/lib/Local/RpcServer.js.map +1 -0
- package/lib/Local/RpcServerBun.d.ts +3 -0
- package/lib/Local/RpcServerBun.d.ts.map +1 -0
- package/lib/Local/RpcServerBun.js +47 -0
- package/lib/Local/RpcServerBun.js.map +1 -0
- package/lib/Local/RpcServerEnvironment.d.ts +20 -0
- package/lib/Local/RpcServerEnvironment.d.ts.map +1 -0
- package/lib/Local/RpcServerEnvironment.js +22 -0
- package/lib/Local/RpcServerEnvironment.js.map +1 -0
- package/lib/Local/RpcServerNode.d.ts +3 -0
- package/lib/Local/RpcServerNode.d.ts.map +1 -0
- package/lib/Local/RpcServerNode.js +43 -0
- package/lib/Local/RpcServerNode.js.map +1 -0
- package/lib/Local/RpcServerSession.d.ts +27 -0
- package/lib/Local/RpcServerSession.d.ts.map +1 -0
- package/lib/Local/RpcServerSession.js +68 -0
- package/lib/Local/RpcServerSession.js.map +1 -0
- package/lib/Local/RpcSpawner.d.ts +21 -0
- package/lib/Local/RpcSpawner.d.ts.map +1 -0
- package/lib/Local/RpcSpawner.js +132 -0
- package/lib/Local/RpcSpawner.js.map +1 -0
- package/lib/Neon/Project.d.ts.map +1 -1
- package/lib/Neon/Project.js +14 -3
- package/lib/Neon/Project.js.map +1 -1
- package/lib/Output.d.ts.map +1 -1
- package/lib/Output.js +9 -2
- package/lib/Output.js.map +1 -1
- package/lib/Phase.d.ts +2 -1
- package/lib/Phase.d.ts.map +1 -1
- package/lib/Phase.js +6 -1
- package/lib/Phase.js.map +1 -1
- package/lib/Plan.d.ts.map +1 -1
- package/lib/Plan.js +14 -3
- package/lib/Plan.js.map +1 -1
- package/lib/Platform.d.ts +8 -6
- package/lib/Platform.d.ts.map +1 -1
- package/lib/Platform.js +33 -3
- package/lib/Platform.js.map +1 -1
- package/lib/Random.d.ts.map +1 -1
- package/lib/Random.js +9 -14
- package/lib/Random.js.map +1 -1
- package/lib/RuntimeContext.d.ts +21 -1
- package/lib/RuntimeContext.d.ts.map +1 -1
- package/lib/RuntimeContext.js +12 -0
- package/lib/RuntimeContext.js.map +1 -1
- package/lib/Stack.d.ts +3 -3
- package/lib/Stack.d.ts.map +1 -1
- package/lib/Stack.js.map +1 -1
- package/lib/State/HttpStateApi.d.ts +2 -2
- package/lib/State/StateEncoding.d.ts +8 -0
- package/lib/State/StateEncoding.d.ts.map +1 -1
- package/lib/State/StateEncoding.js +55 -5
- package/lib/State/StateEncoding.js.map +1 -1
- package/lib/Test/Bun.d.ts.map +1 -1
- package/lib/Test/Bun.js +0 -2
- package/lib/Test/Bun.js.map +1 -1
- package/lib/Test/Vitest.d.ts.map +1 -1
- package/lib/Test/Vitest.js +0 -2
- package/lib/Test/Vitest.js.map +1 -1
- package/lib/Util/Duration.d.ts +14 -0
- package/lib/Util/Duration.d.ts.map +1 -0
- package/lib/Util/Duration.js +18 -0
- package/lib/Util/Duration.js.map +1 -0
- package/lib/Util/PlatformServices.d.ts +7 -0
- package/lib/Util/PlatformServices.d.ts.map +1 -1
- package/lib/Util/PlatformServices.js +22 -11
- package/lib/Util/PlatformServices.js.map +1 -1
- package/lib/Util/camel.d.ts.map +1 -1
- package/lib/Util/camel.js +2 -3
- package/lib/Util/camel.js.map +1 -1
- package/lib/Util/data.d.ts +5 -0
- package/lib/Util/data.d.ts.map +1 -1
- package/lib/Util/data.js +29 -0
- package/lib/Util/data.js.map +1 -1
- package/lib/Util/index.d.ts +0 -6
- package/lib/Util/index.d.ts.map +1 -1
- package/lib/Util/index.js +0 -6
- package/lib/Util/index.js.map +1 -1
- package/lib/Util/stable.d.ts.map +1 -1
- package/lib/Util/stable.js +3 -6
- package/lib/Util/stable.js.map +1 -1
- package/lib/Util/types.d.ts +3 -1
- package/lib/Util/types.d.ts.map +1 -1
- package/lib/Util/types.js +5 -1
- package/lib/Util/types.js.map +1 -1
- package/lib/index.d.ts +2 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -3
- package/lib/index.js.map +1 -1
- package/lib/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +22 -23
- package/src/AWS/Lambda/Function.ts +87 -34
- package/src/AWS/Providers.ts +3 -0
- package/src/Apply.ts +18 -1
- package/src/Auth/AuthProvider.ts +25 -5
- package/src/Auth/Credentials.ts +8 -7
- package/src/Auth/Lock.ts +2 -2
- package/src/Bundle/Bundle.ts +35 -13
- package/src/Bundle/BundleAnalyzerPlugin.ts +33 -0
- package/src/Bundle/RawPlugin.ts +82 -0
- package/src/Bundle/index.ts +2 -0
- package/src/Cli/commands/_shared.ts +47 -4
- package/src/Cli/commands/dev.ts +63 -37
- package/src/Cli/commands/login.ts +20 -4
- package/src/Cli/commands/profile.ts +24 -34
- package/src/Cli/exec.ts +12 -7
- package/src/Cli/main.ts +0 -3
- package/src/Cloudflare/AiGateway/AiGateway.ts +2 -6
- package/src/Cloudflare/BrowserRendering/BrowserRendering.ts +132 -0
- package/src/Cloudflare/BrowserRendering/BrowserRenderingBinding.ts +137 -0
- package/src/Cloudflare/BrowserRendering/index.ts +11 -0
- package/src/Cloudflare/Container/Container.ts +3 -3
- package/src/Cloudflare/Container/StartContainer.ts +1 -2
- package/src/Cloudflare/D1/D1Database.ts +4 -1
- package/src/Cloudflare/D1/D1DatabaseBinding.ts +1 -1
- package/src/Cloudflare/Fetcher.ts +0 -2
- package/src/Cloudflare/Hyperdrive/Hyperdrive.ts +5 -0
- package/src/Cloudflare/Hyperdrive/HyperdriveBinding.ts +41 -43
- package/src/Cloudflare/KV/KVNamespace.ts +4 -0
- package/src/Cloudflare/Local.ts +23 -0
- package/src/Cloudflare/Providers.ts +28 -16
- package/src/Cloudflare/Queue/Queue.ts +3 -0
- package/src/Cloudflare/Queue/QueueConsumer.ts +23 -8
- package/src/Cloudflare/Queue/QueueEventSource.ts +33 -5
- package/src/Cloudflare/R2/R2Bucket.ts +26 -0
- package/src/Cloudflare/SecretsStore/Secret.ts +14 -41
- package/src/Cloudflare/SecretsStore/SecretBinding.ts +11 -11
- package/src/Cloudflare/StateStore/Api.ts +15 -15
- package/src/Cloudflare/StateStore/State.ts +68 -6
- package/src/Cloudflare/StateStore/Store.ts +5 -2
- package/src/Cloudflare/VpcService/VpcService.ts +2 -2
- package/src/Cloudflare/Website/StaticSite.ts +8 -10
- package/src/Cloudflare/Website/Vite.ts +4 -7
- package/src/Cloudflare/Workers/Assets.ts +1 -1
- package/src/Cloudflare/Workers/DurableObjectBridge.ts +7 -5
- package/src/Cloudflare/Workers/DurableObjectNamespace.ts +380 -121
- package/src/Cloudflare/Workers/HttpServer.ts +31 -25
- package/src/Cloudflare/Workers/InferEnv.ts +15 -8
- package/src/Cloudflare/Workers/LocalWorkerProvider.ts +609 -22
- package/src/Cloudflare/Workers/Rpc.ts +50 -0
- package/src/Cloudflare/Workers/RpcDurableObjectNamespace.ts +502 -0
- package/src/Cloudflare/Workers/RpcWorker.ts +562 -0
- package/src/Cloudflare/Workers/Vite.ts +2 -0
- package/src/Cloudflare/Workers/Worker.ts +280 -110
- package/src/Cloudflare/Workers/WorkerAsyncBindings.ts +158 -103
- package/src/Cloudflare/Workers/WorkerBinding.ts +10 -0
- package/src/Cloudflare/Workers/WorkerBridge.ts +10 -9
- package/src/Cloudflare/Workers/WorkerBundle.ts +8 -9
- package/src/Cloudflare/Workers/WorkerRuntimeContext.ts +8 -15
- package/src/Cloudflare/Workers/Workflow.ts +22 -3
- package/src/Cloudflare/Workers/index.ts +2 -0
- package/src/Cloudflare/Zaraz/ZarazConfig.ts +403 -0
- package/src/Cloudflare/Zaraz/ZarazEventTypes.ts +257 -0
- package/src/Cloudflare/Zaraz/index.ts +25 -0
- package/src/Cloudflare/index.ts +2 -0
- package/src/Dependencies.ts +10 -0
- package/src/Deploy.ts +3 -1
- package/src/Diff.ts +13 -0
- package/src/Input.ts +2 -0
- package/src/KeyPair.ts +146 -0
- package/src/Local/RpcProvider.ts +146 -0
- package/src/Local/RpcProviderProxy.ts +86 -0
- package/src/Local/RpcSerialization.ts +225 -0
- package/src/Local/RpcServer.ts +138 -0
- package/src/Local/RpcServerBun.ts +59 -0
- package/src/Local/RpcServerEnvironment.ts +55 -0
- package/src/Local/RpcServerNode.ts +58 -0
- package/src/Local/RpcServerSession.ts +87 -0
- package/src/Local/RpcSpawner.ts +196 -0
- package/src/Neon/Project.ts +16 -3
- package/src/Output.ts +8 -2
- package/src/Phase.ts +8 -0
- package/src/Plan.ts +16 -3
- package/src/Platform.ts +74 -27
- package/src/Random.ts +22 -27
- package/src/RuntimeContext.ts +23 -1
- package/src/Stack.ts +3 -3
- package/src/State/StateEncoding.ts +58 -7
- package/src/Test/Bun.ts +0 -3
- package/src/Test/Vitest.ts +0 -3
- package/src/Util/Duration.ts +21 -0
- package/src/Util/PlatformServices.ts +41 -27
- package/src/Util/camel.ts +3 -5
- package/src/Util/data.ts +38 -0
- package/src/Util/index.ts +0 -6
- package/src/Util/stable.ts +4 -10
- package/src/Util/types.ts +9 -2
- package/src/index.ts +2 -3
- package/lib/Cloudflare/Local/Sidecar.d.ts +0 -63
- package/lib/Cloudflare/Local/Sidecar.d.ts.map +0 -1
- package/lib/Cloudflare/Local/Sidecar.js +0 -50
- package/lib/Cloudflare/Local/Sidecar.js.map +0 -1
- package/lib/Cloudflare/Local/SidecarHandlers.d.ts +0 -8
- package/lib/Cloudflare/Local/SidecarHandlers.d.ts.map +0 -1
- package/lib/Cloudflare/Local/SidecarHandlers.js +0 -381
- package/lib/Cloudflare/Local/SidecarHandlers.js.map +0 -1
- package/lib/Cloudflare/Local/SidecarServer.d.ts +0 -2
- package/lib/Cloudflare/Local/SidecarServer.d.ts.map +0 -1
- package/lib/Cloudflare/Local/SidecarServer.js +0 -34
- package/lib/Cloudflare/Local/SidecarServer.js.map +0 -1
- package/lib/Secret.d.ts +0 -50
- package/lib/Secret.d.ts.map +0 -1
- package/lib/Secret.js +0 -23
- package/lib/Secret.js.map +0 -1
- package/lib/Sidecar/Lock.d.ts +0 -23
- package/lib/Sidecar/Lock.d.ts.map +0 -1
- package/lib/Sidecar/Lock.js +0 -39
- package/lib/Sidecar/Lock.js.map +0 -1
- package/lib/Sidecar/RpcClient.d.ts +0 -15
- package/lib/Sidecar/RpcClient.d.ts.map +0 -1
- package/lib/Sidecar/RpcClient.js +0 -78
- package/lib/Sidecar/RpcClient.js.map +0 -1
- package/lib/Sidecar/RpcHandler.d.ts +0 -51
- package/lib/Sidecar/RpcHandler.d.ts.map +0 -1
- package/lib/Sidecar/RpcHandler.js +0 -87
- package/lib/Sidecar/RpcHandler.js.map +0 -1
- package/lib/Sidecar/RpcPaths.d.ts +0 -19
- package/lib/Sidecar/RpcPaths.d.ts.map +0 -1
- package/lib/Sidecar/RpcPaths.js +0 -31
- package/lib/Sidecar/RpcPaths.js.map +0 -1
- package/lib/Sidecar/RpcServer.d.ts +0 -30
- package/lib/Sidecar/RpcServer.d.ts.map +0 -1
- package/lib/Sidecar/RpcServer.js +0 -105
- package/lib/Sidecar/RpcServer.js.map +0 -1
- package/lib/Sidecar/RpcServerBun.d.ts +0 -4
- package/lib/Sidecar/RpcServerBun.d.ts.map +0 -1
- package/lib/Sidecar/RpcServerBun.js +0 -28
- package/lib/Sidecar/RpcServerBun.js.map +0 -1
- package/lib/Sidecar/RpcServerNode.d.ts +0 -4
- package/lib/Sidecar/RpcServerNode.d.ts.map +0 -1
- package/lib/Sidecar/RpcServerNode.js +0 -39
- package/lib/Sidecar/RpcServerNode.js.map +0 -1
- package/lib/Sidecar/RpcServices.d.ts +0 -6
- package/lib/Sidecar/RpcServices.d.ts.map +0 -1
- package/lib/Sidecar/RpcServices.js +0 -29
- package/lib/Sidecar/RpcServices.js.map +0 -1
- package/lib/Trait.d.ts +0 -43
- package/lib/Trait.d.ts.map +0 -1
- package/lib/Trait.js +0 -17
- package/lib/Trait.js.map +0 -1
- package/lib/Util/LocalhostDns.d.ts +0 -23
- package/lib/Util/LocalhostDns.d.ts.map +0 -1
- package/lib/Util/LocalhostDns.js +0 -46
- package/lib/Util/LocalhostDns.js.map +0 -1
- package/lib/Util/assert-never.d.ts +0 -12
- package/lib/Util/assert-never.d.ts.map +0 -1
- package/lib/Util/assert-never.js +0 -11
- package/lib/Util/assert-never.js.map +0 -1
- package/lib/Util/class.d.ts +0 -3
- package/lib/Util/class.d.ts.map +0 -1
- package/lib/Util/class.js +0 -1
- package/lib/Util/class.js.map +0 -1
- package/lib/Util/ignore.d.ts +0 -40
- package/lib/Util/ignore.d.ts.map +0 -1
- package/lib/Util/ignore.js +0 -591
- package/lib/Util/ignore.js.map +0 -1
- package/lib/Util/instance.d.ts +0 -4
- package/lib/Util/instance.d.ts.map +0 -1
- package/lib/Util/instance.js +0 -1
- package/lib/Util/instance.js.map +0 -1
- package/lib/Util/pointer.d.ts +0 -5
- package/lib/Util/pointer.d.ts.map +0 -1
- package/lib/Util/pointer.js +0 -1
- package/lib/Util/pointer.js.map +0 -1
- package/lib/Util/schema-to-type.d.ts +0 -42
- package/lib/Util/schema-to-type.d.ts.map +0 -1
- package/lib/Util/schema-to-type.js +0 -364
- package/lib/Util/schema-to-type.js.map +0 -1
- package/lib/Util/todo.d.ts +0 -3
- package/lib/Util/todo.d.ts.map +0 -1
- package/lib/Util/todo.js +0 -3
- package/lib/Util/todo.js.map +0 -1
- package/lib/Variable.d.ts +0 -29
- package/lib/Variable.d.ts.map +0 -1
- package/lib/Variable.js +0 -9
- package/lib/Variable.js.map +0 -1
- package/src/Cloudflare/Local/Sidecar.ts +0 -81
- package/src/Cloudflare/Local/SidecarHandlers.ts +0 -491
- package/src/Cloudflare/Local/SidecarServer.ts +0 -70
- package/src/Secret.ts +0 -87
- package/src/Sidecar/Lock.ts +0 -66
- package/src/Sidecar/RpcClient.ts +0 -142
- package/src/Sidecar/RpcHandler.ts +0 -205
- package/src/Sidecar/RpcPaths.ts +0 -39
- package/src/Sidecar/RpcServer.ts +0 -153
- package/src/Sidecar/RpcServerBun.ts +0 -41
- package/src/Sidecar/RpcServerNode.ts +0 -51
- package/src/Sidecar/RpcServices.ts +0 -48
- package/src/Trait.ts +0 -105
- package/src/Util/LocalhostDns.ts +0 -52
- package/src/Util/assert-never.ts +0 -18
- package/src/Util/class.ts +0 -7
- package/src/Util/ignore.ts +0 -815
- package/src/Util/instance.ts +0 -9
- package/src/Util/pointer.ts +0 -5
- package/src/Util/schema-to-type.ts +0 -456
- package/src/Util/todo.ts +0 -4
- package/src/Variable.ts +0 -44
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import * as Console from "effect/Console";
|
|
2
|
+
import * as Context from "effect/Context";
|
|
3
|
+
import * as Deferred from "effect/Deferred";
|
|
4
|
+
import * as Effect from "effect/Effect";
|
|
5
|
+
import * as Layer from "effect/Layer";
|
|
6
|
+
import type * as Scope from "effect/Scope";
|
|
7
|
+
import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient";
|
|
8
|
+
import type { HttpClient } from "effect/unstable/http/HttpClient";
|
|
9
|
+
import type { ProviderService } from "../Provider.ts";
|
|
10
|
+
import type { ResourceLike } from "../Resource.ts";
|
|
11
|
+
import {
|
|
12
|
+
platformLayer,
|
|
13
|
+
PlatformServices,
|
|
14
|
+
runMain,
|
|
15
|
+
} from "../Util/PlatformServices.ts";
|
|
16
|
+
import * as RpcSerialization from "./RpcSerialization.ts";
|
|
17
|
+
import * as RpcServerEnvironment from "./RpcServerEnvironment.ts";
|
|
18
|
+
import {
|
|
19
|
+
makeServerRpcSession,
|
|
20
|
+
type ServerRpcSession,
|
|
21
|
+
type ServerWebSocketLike,
|
|
22
|
+
} from "./RpcServerSession.ts";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A service that exposes one or more resource providers over RPC.
|
|
26
|
+
* This returns `never` because it is meant to be used with `Layer.launch` (see {@link launch}).
|
|
27
|
+
*/
|
|
28
|
+
export class RpcServer extends Context.Service<RpcServer, never>()(
|
|
29
|
+
"alchemy/Local/RpcServer",
|
|
30
|
+
) {}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The RPC API that is implemented by the server and consumed by {@link RpcProviderProxy}.
|
|
34
|
+
*/
|
|
35
|
+
export interface RpcProxyApi {
|
|
36
|
+
/**
|
|
37
|
+
* Retrieves a provider from the RPC server context.
|
|
38
|
+
* The consumer must unwrap the provider using {@link RpcSerialization.unwrapRpcHandlers} before using it.
|
|
39
|
+
*/
|
|
40
|
+
readonly getProvider: <R extends ResourceLike>(
|
|
41
|
+
type: R["Type"],
|
|
42
|
+
) => Promise<RpcSerialization.RpcWrapped<ProviderService<R>>>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const serverPlatformLayer = platformLayer({
|
|
46
|
+
bun: async () => {
|
|
47
|
+
const { RpcServerBun } = await import("./RpcServerBun.ts");
|
|
48
|
+
return RpcServerBun;
|
|
49
|
+
},
|
|
50
|
+
node: async () => {
|
|
51
|
+
const { RpcServerNode } = await import("./RpcServerNode.ts");
|
|
52
|
+
return RpcServerNode;
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Launches an RPC server that serves the given providers.
|
|
58
|
+
* Alchemy globals such as `AlchemyContext`, `Profile`, and `Stack` are inherited from the parent via {@link RpcServerEnvironment.fromEnv} and should not be provided manually.
|
|
59
|
+
* `PlatformServices` and `HttpClient` are also included.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* RpcServer.launch(
|
|
64
|
+
* Layer.merge(
|
|
65
|
+
* FunctionProvider,
|
|
66
|
+
* QueueProvider,
|
|
67
|
+
* ),
|
|
68
|
+
* );
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @param providers - A layer containing the providers to serve.
|
|
72
|
+
*/
|
|
73
|
+
export const launch = <ROut, E>(
|
|
74
|
+
providers: Layer.Layer<
|
|
75
|
+
ROut,
|
|
76
|
+
E,
|
|
77
|
+
| Scope.Scope
|
|
78
|
+
| RpcServerEnvironment.RpcEnvironmentServices
|
|
79
|
+
| PlatformServices
|
|
80
|
+
| HttpClient
|
|
81
|
+
>,
|
|
82
|
+
) =>
|
|
83
|
+
serverPlatformLayer.pipe(
|
|
84
|
+
Layer.provide(providers),
|
|
85
|
+
Layer.provide(RpcServerEnvironment.fromEnv()),
|
|
86
|
+
Layer.provide(Layer.merge(PlatformServices, FetchHttpClient.layer)),
|
|
87
|
+
Layer.launch,
|
|
88
|
+
Effect.scoped,
|
|
89
|
+
runMain,
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Constructs an `RpcServer` layer using the given server implementation.
|
|
94
|
+
* @param serve - A function that spawns a websocket server and returns its URL.
|
|
95
|
+
* @returns An `RpcServer` layer.
|
|
96
|
+
*/
|
|
97
|
+
export const layerServer = (
|
|
98
|
+
serve: (handlers: {
|
|
99
|
+
/** Creates a new RPC session over the given websocket. */
|
|
100
|
+
createRpcSession: (
|
|
101
|
+
ws: ServerWebSocketLike,
|
|
102
|
+
) => ServerRpcSession<RpcProxyApi>;
|
|
103
|
+
/** Called when the parent connection, indicated by the `/parent` path, is established. */
|
|
104
|
+
parentConnected: () => void;
|
|
105
|
+
/** Called when the parent disconnects. The server will shut down when this is called. */
|
|
106
|
+
parentDisconnected: () => void;
|
|
107
|
+
}) => Effect.Effect<{ readonly url: string }, never, Scope.Scope>,
|
|
108
|
+
) =>
|
|
109
|
+
Layer.effect(
|
|
110
|
+
RpcServer,
|
|
111
|
+
Effect.gen(function* () {
|
|
112
|
+
const context = yield* Effect.context();
|
|
113
|
+
const connected = yield* Deferred.make<void>();
|
|
114
|
+
const disconnected = yield* Deferred.make<void>();
|
|
115
|
+
const { url } = yield* serve({
|
|
116
|
+
createRpcSession: (ws) =>
|
|
117
|
+
makeServerRpcSession<RpcProxyApi>(ws, {
|
|
118
|
+
getProvider: async <R extends ResourceLike>(type: R["Type"]) => {
|
|
119
|
+
const provider = context.mapUnsafe.get(type);
|
|
120
|
+
if (!provider) {
|
|
121
|
+
throw new Error(`Provider "${type}" not found`);
|
|
122
|
+
}
|
|
123
|
+
return RpcSerialization.wrapRpcHandlers(
|
|
124
|
+
provider as ProviderService<R>,
|
|
125
|
+
["tail"],
|
|
126
|
+
);
|
|
127
|
+
},
|
|
128
|
+
}),
|
|
129
|
+
parentConnected: () => Deferred.doneUnsafe(connected, Effect.void),
|
|
130
|
+
parentDisconnected: () =>
|
|
131
|
+
Deferred.doneUnsafe(disconnected, Effect.void),
|
|
132
|
+
});
|
|
133
|
+
yield* Console.log(`<ALCHEMY_RPC_ADDRESS>${url}</ALCHEMY_RPC_ADDRESS>`);
|
|
134
|
+
yield* Deferred.await(connected).pipe(Effect.timeout("10 seconds")); // TODO(john): should the timeout be shorter?
|
|
135
|
+
yield* Deferred.await(disconnected);
|
|
136
|
+
return yield* Effect.interrupt;
|
|
137
|
+
}),
|
|
138
|
+
);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as RpcServer from "./RpcServer.ts";
|
|
3
|
+
import type { ServerRpcSession } from "./RpcServerSession.ts";
|
|
4
|
+
|
|
5
|
+
export const RpcServerBun = RpcServer.layerServer(
|
|
6
|
+
Effect.fnUntraced(function* ({
|
|
7
|
+
parentConnected,
|
|
8
|
+
parentDisconnected,
|
|
9
|
+
createRpcSession,
|
|
10
|
+
}) {
|
|
11
|
+
const server = yield* Effect.sync(() =>
|
|
12
|
+
Bun.serve<
|
|
13
|
+
{ type: "session"; session: ServerRpcSession<any> } | { type: "parent" }
|
|
14
|
+
>({
|
|
15
|
+
port: 0,
|
|
16
|
+
fetch: (request, server) => {
|
|
17
|
+
const url = new URL(request.url);
|
|
18
|
+
if (
|
|
19
|
+
server.upgrade(request, {
|
|
20
|
+
data:
|
|
21
|
+
url.pathname === "/parent" ? { type: "parent" } : undefined!,
|
|
22
|
+
})
|
|
23
|
+
) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
return new Response("Upgrade failed", { status: 400 });
|
|
27
|
+
},
|
|
28
|
+
websocket: {
|
|
29
|
+
open: (ws) => {
|
|
30
|
+
if (ws.data && ws.data.type === "parent") {
|
|
31
|
+
parentConnected();
|
|
32
|
+
} else {
|
|
33
|
+
ws.data = {
|
|
34
|
+
type: "session",
|
|
35
|
+
session: createRpcSession(ws),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
message: (ws, message) => {
|
|
40
|
+
if (ws.data.type === "session") {
|
|
41
|
+
ws.data.session.dispatch.message(message);
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
close: (ws, code, reason) => {
|
|
45
|
+
if (ws.data.type === "session") {
|
|
46
|
+
ws.data.session.dispatch.close(code, reason);
|
|
47
|
+
} else if (ws.data.type === "parent") {
|
|
48
|
+
parentDisconnected();
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
}),
|
|
53
|
+
);
|
|
54
|
+
yield* Effect.addFinalizer(() => Effect.sync(() => server.stop(true)));
|
|
55
|
+
return {
|
|
56
|
+
url: `ws://${server.hostname}:${server.port}`,
|
|
57
|
+
};
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as Config from "effect/Config";
|
|
2
|
+
import * as ConfigProvider from "effect/ConfigProvider";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Layer from "effect/Layer";
|
|
5
|
+
import * as Option from "effect/Option";
|
|
6
|
+
import { AlchemyContext } from "../AlchemyContext.ts";
|
|
7
|
+
import { AuthProviders } from "../Auth/AuthProvider.ts";
|
|
8
|
+
import { CredentialsStoreLive } from "../Auth/Credentials.ts";
|
|
9
|
+
import { ProfileLive, withProfileOverride } from "../Auth/Profile.ts";
|
|
10
|
+
import { Stack } from "../Stack.ts";
|
|
11
|
+
import { Stage } from "../Stage.ts";
|
|
12
|
+
import { loadConfigProvider } from "../Util/ConfigProvider.ts";
|
|
13
|
+
|
|
14
|
+
export interface RpcServerEnvironment {
|
|
15
|
+
alchemyContext: AlchemyContext["Service"];
|
|
16
|
+
profile: string | undefined;
|
|
17
|
+
envFile: string | undefined;
|
|
18
|
+
stack: {
|
|
19
|
+
name: string;
|
|
20
|
+
stage: string;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type RpcEnvironmentServices = Layer.Success<ReturnType<typeof layer>>;
|
|
25
|
+
|
|
26
|
+
export const layer = (environment: RpcServerEnvironment) =>
|
|
27
|
+
Layer.mergeAll(
|
|
28
|
+
ProfileLive,
|
|
29
|
+
CredentialsStoreLive,
|
|
30
|
+
Layer.succeed(AuthProviders, {}),
|
|
31
|
+
ConfigProvider.layer(
|
|
32
|
+
loadConfigProvider(Option.fromNullishOr(environment.envFile)).pipe(
|
|
33
|
+
Effect.map((base) => withProfileOverride(base, environment.profile)),
|
|
34
|
+
),
|
|
35
|
+
),
|
|
36
|
+
Layer.succeed(AlchemyContext, environment.alchemyContext),
|
|
37
|
+
Layer.succeed(Stack, {
|
|
38
|
+
name: environment.stack.name,
|
|
39
|
+
stage: environment.stack.stage,
|
|
40
|
+
resources: {},
|
|
41
|
+
bindings: {},
|
|
42
|
+
actions: {},
|
|
43
|
+
}),
|
|
44
|
+
Layer.succeed(Stage, environment.stack.stage),
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
export const RPC_SERVER_ENVIRONMENT_KEY =
|
|
48
|
+
"ALCHEMY_RPC_SERVER_ENVIRONMENT" as const;
|
|
49
|
+
|
|
50
|
+
export const fromEnv = () =>
|
|
51
|
+
Config.string(RPC_SERVER_ENVIRONMENT_KEY).pipe(
|
|
52
|
+
Config.map(JSON.parse),
|
|
53
|
+
Effect.map((environment) => layer(environment)),
|
|
54
|
+
Layer.unwrap,
|
|
55
|
+
);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { WebSocketServer, type Server } from "ws";
|
|
3
|
+
import * as RpcServer from "./RpcServer.ts";
|
|
4
|
+
|
|
5
|
+
export const RpcServerNode = RpcServer.layerServer(
|
|
6
|
+
Effect.fnUntraced(function* ({
|
|
7
|
+
parentConnected,
|
|
8
|
+
parentDisconnected,
|
|
9
|
+
createRpcSession,
|
|
10
|
+
}) {
|
|
11
|
+
const server = new WebSocketServer({ host: "127.0.0.1", port: 0 });
|
|
12
|
+
const url = yield* Effect.callback<string>((resume) => {
|
|
13
|
+
server.on("connection", (ws, req) => {
|
|
14
|
+
if (req.url?.startsWith("/parent")) {
|
|
15
|
+
parentConnected();
|
|
16
|
+
ws.on("close", () => {
|
|
17
|
+
parentDisconnected();
|
|
18
|
+
});
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const session = createRpcSession(ws);
|
|
22
|
+
ws.on("message", (data) => {
|
|
23
|
+
session.dispatch.message(data.toString());
|
|
24
|
+
});
|
|
25
|
+
ws.on("close", (code, reason) => {
|
|
26
|
+
session.dispatch.close(code, reason.toString());
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
server.on("error", (error) => {
|
|
30
|
+
resume(Effect.die(error));
|
|
31
|
+
});
|
|
32
|
+
server.on("listening", () => {
|
|
33
|
+
resume(getServerAddress(server));
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
yield* Effect.addFinalizer(() => Effect.sync(() => server.close()));
|
|
37
|
+
return { url };
|
|
38
|
+
}),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
function getServerAddress(server: Server): Effect.Effect<string> {
|
|
42
|
+
const address = server.address();
|
|
43
|
+
if (
|
|
44
|
+
typeof address === "object" &&
|
|
45
|
+
address !== null &&
|
|
46
|
+
"address" in address &&
|
|
47
|
+
"port" in address
|
|
48
|
+
) {
|
|
49
|
+
return Effect.succeed(
|
|
50
|
+
`ws://${address.address === "::" ? "localhost" : address.address}:${address.port}`,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
return Effect.die(
|
|
54
|
+
new Error(
|
|
55
|
+
`Server address is not an object with address and port properties: ${JSON.stringify(address)}`,
|
|
56
|
+
),
|
|
57
|
+
);
|
|
58
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { RpcSession, type RpcCompatible, type RpcTransport } from "capnweb";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A platform-agnostic interface for a server-side WebSocket.
|
|
5
|
+
*/
|
|
6
|
+
export interface ServerWebSocketLike {
|
|
7
|
+
send: (message: string) => any | Promise<any>;
|
|
8
|
+
close: (code?: number, reason?: string) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Represents a websocket RPC session with capnweb.
|
|
13
|
+
* Use the `dispatch` object to handle messages that are received from the client.
|
|
14
|
+
*/
|
|
15
|
+
export type ServerRpcSession<T extends RpcCompatible<T>> = ReturnType<
|
|
16
|
+
typeof makeServerRpcSession<T>
|
|
17
|
+
>;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Constructs a ServerRpcSession using capnweb.
|
|
21
|
+
* @param ws - The WebSocket to use for the session.
|
|
22
|
+
* @param main - The main object to use for the session.
|
|
23
|
+
* @returns A ServerRpcSession.
|
|
24
|
+
*/
|
|
25
|
+
export function makeServerRpcSession<T extends RpcCompatible<T>>(
|
|
26
|
+
ws: ServerWebSocketLike,
|
|
27
|
+
main: T,
|
|
28
|
+
) {
|
|
29
|
+
const { transport, dispatch } = makeWebSocketRpcTransport(ws);
|
|
30
|
+
const session = new RpcSession(transport, main);
|
|
31
|
+
return { session, dispatch };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function makeWebSocketRpcTransport(ws: ServerWebSocketLike) {
|
|
35
|
+
let receiveQueue: Array<string> = [];
|
|
36
|
+
let receiveResolver: ((value: string) => void) | undefined;
|
|
37
|
+
let receiveRejecter: ((reason: unknown) => void) | undefined;
|
|
38
|
+
let error: unknown | undefined;
|
|
39
|
+
return {
|
|
40
|
+
transport: {
|
|
41
|
+
send: async (message: string) => await ws.send(message),
|
|
42
|
+
receive: async () => {
|
|
43
|
+
const next = receiveQueue.shift();
|
|
44
|
+
if (next) {
|
|
45
|
+
return next;
|
|
46
|
+
} else if (error) {
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
return new Promise<string>((resolve, reject) => {
|
|
50
|
+
receiveResolver = resolve;
|
|
51
|
+
receiveRejecter = reject;
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
abort: (reason: unknown) => {
|
|
55
|
+
const message =
|
|
56
|
+
reason instanceof Error ? reason.message : String(reason);
|
|
57
|
+
ws.close(3000, message);
|
|
58
|
+
error ??= reason;
|
|
59
|
+
},
|
|
60
|
+
} satisfies RpcTransport,
|
|
61
|
+
dispatch: {
|
|
62
|
+
message: (data: string | Buffer<ArrayBuffer>) => {
|
|
63
|
+
if (error) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
data = typeof data === "string" ? data : data.toString("utf-8");
|
|
67
|
+
if (receiveResolver) {
|
|
68
|
+
receiveResolver(data);
|
|
69
|
+
receiveResolver = undefined;
|
|
70
|
+
receiveRejecter = undefined;
|
|
71
|
+
} else {
|
|
72
|
+
receiveQueue.push(data);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
close: (code: number, reason: string) => {
|
|
76
|
+
if (!error) {
|
|
77
|
+
error = new Error(`WebSocket closed with code ${code}: ${reason}`);
|
|
78
|
+
if (receiveRejecter) {
|
|
79
|
+
receiveRejecter(error);
|
|
80
|
+
receiveRejecter = undefined;
|
|
81
|
+
receiveResolver = undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { exitHook } from "@alchemy.run/node-utils/exit-hook";
|
|
2
|
+
import * as Cache from "effect/Cache";
|
|
3
|
+
import * as Context from "effect/Context";
|
|
4
|
+
import * as Deferred from "effect/Deferred";
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
6
|
+
import * as Layer from "effect/Layer";
|
|
7
|
+
import type { PlatformError } from "effect/PlatformError";
|
|
8
|
+
import * as Scope from "effect/Scope";
|
|
9
|
+
import * as Stream from "effect/Stream";
|
|
10
|
+
import * as HttpServer from "effect/unstable/http/HttpServer";
|
|
11
|
+
import { HttpServerRequest } from "effect/unstable/http/HttpServerRequest";
|
|
12
|
+
import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse";
|
|
13
|
+
import * as ChildProcess from "effect/unstable/process/ChildProcess";
|
|
14
|
+
import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner";
|
|
15
|
+
import * as NodeChildProcess from "node:child_process";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
import { httpServer } from "../Util/PlatformServices.ts";
|
|
18
|
+
import {
|
|
19
|
+
RPC_SERVER_ENVIRONMENT_KEY,
|
|
20
|
+
type RpcServerEnvironment,
|
|
21
|
+
} from "./RpcServerEnvironment.ts";
|
|
22
|
+
|
|
23
|
+
export class RpcSpawner extends Context.Service<
|
|
24
|
+
RpcSpawner,
|
|
25
|
+
{
|
|
26
|
+
readonly url: string;
|
|
27
|
+
}
|
|
28
|
+
>()("alchemy/Local/RpcSpawner") {}
|
|
29
|
+
|
|
30
|
+
export interface RpcSpawnPayload extends Pick<
|
|
31
|
+
RpcServerEnvironment,
|
|
32
|
+
"alchemyContext" | "stack"
|
|
33
|
+
> {
|
|
34
|
+
serverEntryUrl: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const make = Effect.fnUntraced(function* ({
|
|
38
|
+
profile,
|
|
39
|
+
envFile,
|
|
40
|
+
}: Pick<RpcServerEnvironment, "profile" | "envFile">) {
|
|
41
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
42
|
+
const scope = yield* Effect.scope;
|
|
43
|
+
const cache = yield* Cache.make({
|
|
44
|
+
lookup: (payload: RpcSpawnPayload) =>
|
|
45
|
+
spawn(payload).pipe(Scope.provide(scope)),
|
|
46
|
+
capacity: Infinity,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const spawn = Effect.fnUntraced(function* ({
|
|
50
|
+
serverEntryUrl,
|
|
51
|
+
alchemyContext,
|
|
52
|
+
stack,
|
|
53
|
+
}: RpcSpawnPayload) {
|
|
54
|
+
const bin = typeof globalThis.Bun !== "undefined" ? "bun" : "node";
|
|
55
|
+
const main = fileURLToPath(serverEntryUrl);
|
|
56
|
+
const environment: RpcServerEnvironment = {
|
|
57
|
+
profile,
|
|
58
|
+
envFile,
|
|
59
|
+
alchemyContext,
|
|
60
|
+
stack,
|
|
61
|
+
};
|
|
62
|
+
const command = ChildProcess.make(
|
|
63
|
+
bin,
|
|
64
|
+
{
|
|
65
|
+
bun: ["run", main],
|
|
66
|
+
// Under Node, transparently strip TypeScript types so that `.ts`
|
|
67
|
+
// entry points work the same way they do under Bun. Mirrors what
|
|
68
|
+
// `dev.ts` already does for the outer process, so the dev experience
|
|
69
|
+
// is symmetric on both runtimes whether the entry came from `src/`
|
|
70
|
+
// (dev/tests) or `lib/` (published packages).
|
|
71
|
+
node: main.endsWith(".ts")
|
|
72
|
+
? [
|
|
73
|
+
"--experimental-transform-types",
|
|
74
|
+
"--no-warnings=ExperimentalWarning",
|
|
75
|
+
main,
|
|
76
|
+
]
|
|
77
|
+
: [main],
|
|
78
|
+
}[bin],
|
|
79
|
+
{
|
|
80
|
+
stdout: "pipe",
|
|
81
|
+
stderr: "inherit",
|
|
82
|
+
detached: false,
|
|
83
|
+
env: {
|
|
84
|
+
[RPC_SERVER_ENVIRONMENT_KEY]: JSON.stringify(environment),
|
|
85
|
+
},
|
|
86
|
+
extendEnv: true,
|
|
87
|
+
},
|
|
88
|
+
);
|
|
89
|
+
const handle = yield* spawner.spawn(command);
|
|
90
|
+
const unregister = exitHook(() => {
|
|
91
|
+
killProcessGroup(handle.pid, "SIGKILL");
|
|
92
|
+
});
|
|
93
|
+
const kill = handle
|
|
94
|
+
.kill({ forceKillAfter: "500 millis" })
|
|
95
|
+
.pipe(Effect.tap(() => Effect.sync(unregister)));
|
|
96
|
+
yield* Effect.addFinalizer(() => kill.pipe(Effect.ignore));
|
|
97
|
+
const url = yield* getRpcAddress(handle.stdout);
|
|
98
|
+
const ws = yield* Effect.acquireRelease(
|
|
99
|
+
Effect.sync(() => new WebSocket(new URL("/parent", url))),
|
|
100
|
+
(ws) => Effect.sync(() => ws.close()),
|
|
101
|
+
);
|
|
102
|
+
return {
|
|
103
|
+
url,
|
|
104
|
+
isRunning: Effect.zipWith(
|
|
105
|
+
handle.isRunning,
|
|
106
|
+
Effect.sync(
|
|
107
|
+
() =>
|
|
108
|
+
ws.readyState === WebSocket.CONNECTING ||
|
|
109
|
+
ws.readyState === WebSocket.OPEN,
|
|
110
|
+
),
|
|
111
|
+
(a, b) => a && b,
|
|
112
|
+
{ concurrent: true },
|
|
113
|
+
),
|
|
114
|
+
kill,
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const register = Effect.fnUntraced(function* (
|
|
119
|
+
payload: RpcSpawnPayload,
|
|
120
|
+
attempt = 0,
|
|
121
|
+
): Effect.fn.Return<string, PlatformError> {
|
|
122
|
+
const child = yield* Cache.get(cache, payload);
|
|
123
|
+
if (yield* child.isRunning) {
|
|
124
|
+
return child.url;
|
|
125
|
+
}
|
|
126
|
+
if (attempt > 3) {
|
|
127
|
+
return yield* Effect.die(
|
|
128
|
+
new Error(
|
|
129
|
+
`Failed to spawn RPC server for "${payload.serverEntryUrl}" after ${attempt} attempts.`,
|
|
130
|
+
),
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
yield* child.kill;
|
|
134
|
+
yield* Cache.invalidate(cache, payload);
|
|
135
|
+
return yield* register(payload, attempt + 1);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const server = yield* HttpServer.HttpServer;
|
|
139
|
+
|
|
140
|
+
yield* server.serve(
|
|
141
|
+
Effect.gen(function* () {
|
|
142
|
+
const request = yield* HttpServerRequest;
|
|
143
|
+
const payload = (yield* request.json) as unknown as RpcSpawnPayload;
|
|
144
|
+
const url = yield* register(payload);
|
|
145
|
+
return HttpServerResponse.text(url);
|
|
146
|
+
}),
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
return RpcSpawner.of({
|
|
150
|
+
url: HttpServer.formatAddress(server.address),
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
export const layerServer = (
|
|
155
|
+
environment: Pick<RpcServerEnvironment, "profile" | "envFile">,
|
|
156
|
+
) =>
|
|
157
|
+
Layer.effect(RpcSpawner, make(environment)).pipe(Layer.provide(httpServer()));
|
|
158
|
+
|
|
159
|
+
const RPC_ADDRESS_REGEX =
|
|
160
|
+
/(<ALCHEMY_RPC_ADDRESS>)(.+)(<\/ALCHEMY_RPC_ADDRESS>)/;
|
|
161
|
+
|
|
162
|
+
const getRpcAddress = (stdout: Stream.Stream<Uint8Array, PlatformError>) =>
|
|
163
|
+
Effect.gen(function* () {
|
|
164
|
+
const address = yield* Deferred.make<string>();
|
|
165
|
+
let done = false;
|
|
166
|
+
yield* stdout.pipe(
|
|
167
|
+
Stream.decodeText,
|
|
168
|
+
Stream.splitLines,
|
|
169
|
+
Stream.runForEach((line) => {
|
|
170
|
+
if (done) {
|
|
171
|
+
console.log(line);
|
|
172
|
+
} else {
|
|
173
|
+
const match = line.match(RPC_ADDRESS_REGEX);
|
|
174
|
+
if (match) {
|
|
175
|
+
done = true;
|
|
176
|
+
return Deferred.succeed(address, match[2]);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return Effect.void;
|
|
180
|
+
}),
|
|
181
|
+
Effect.forkScoped,
|
|
182
|
+
);
|
|
183
|
+
return yield* Deferred.await(address);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const killProcessGroup = (pid: number, signal: NodeJS.Signals) => {
|
|
187
|
+
try {
|
|
188
|
+
if (process.platform === "win32") {
|
|
189
|
+
NodeChildProcess.execSync(`taskkill /pid ${pid} /T /F`);
|
|
190
|
+
} else {
|
|
191
|
+
process.kill(-pid, signal);
|
|
192
|
+
}
|
|
193
|
+
} catch {
|
|
194
|
+
// ignore errors during best-effort cleanup
|
|
195
|
+
}
|
|
196
|
+
};
|
package/src/Neon/Project.ts
CHANGED
|
@@ -136,7 +136,7 @@ const findProjectByName = (name: string) =>
|
|
|
136
136
|
Effect.gen(function* () {
|
|
137
137
|
const matches: ListProjectsOutput["projects"][number][] = [];
|
|
138
138
|
let cursor: string | undefined;
|
|
139
|
-
|
|
139
|
+
while (true) {
|
|
140
140
|
const page = yield* listProjects({
|
|
141
141
|
search: name,
|
|
142
142
|
...(cursor !== undefined ? { cursor } : {}),
|
|
@@ -144,8 +144,21 @@ const findProjectByName = (name: string) =>
|
|
|
144
144
|
for (const p of page.projects) {
|
|
145
145
|
if (p.name === name) matches.push(p);
|
|
146
146
|
}
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
const nextCursor = page.pagination?.cursor;
|
|
148
|
+
// Neon returns a `pagination.cursor` on every response — it's the
|
|
149
|
+
// `created_at` of the last row, not a "has next page" flag — so we
|
|
150
|
+
// can't loop on cursor presence alone or we spin forever re-fetching
|
|
151
|
+
// empty/identical pages. Stop once a page comes back empty or the
|
|
152
|
+
// cursor stops advancing.
|
|
153
|
+
if (
|
|
154
|
+
page.projects.length === 0 ||
|
|
155
|
+
nextCursor === undefined ||
|
|
156
|
+
nextCursor === cursor
|
|
157
|
+
) {
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
cursor = nextCursor;
|
|
161
|
+
}
|
|
149
162
|
return matches;
|
|
150
163
|
});
|
|
151
164
|
|
package/src/Output.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as Data from "effect/Data";
|
|
2
|
+
import * as Duration from "effect/Duration";
|
|
2
3
|
import * as Effect from "effect/Effect";
|
|
3
4
|
import { pipe } from "effect/Function";
|
|
4
5
|
import type { Pipeable } from "effect/Pipeable";
|
|
@@ -6,7 +7,7 @@ import * as Redacted from "effect/Redacted";
|
|
|
6
7
|
import { SingleShotGen } from "effect/Utils";
|
|
7
8
|
import { getRefMetadata, isRef, type Ref } from "./Ref.ts";
|
|
8
9
|
import { isResource, type Resource, type ResourceLike } from "./Resource.ts";
|
|
9
|
-
import { RuntimeContext } from "./RuntimeContext.ts";
|
|
10
|
+
import { RuntimeContext, sanitizeKey } from "./RuntimeContext.ts";
|
|
10
11
|
import { Stack } from "./Stack.ts";
|
|
11
12
|
import { Stage } from "./Stage.ts";
|
|
12
13
|
import * as State from "./State/State.ts";
|
|
@@ -112,9 +113,11 @@ export abstract class BaseExpr<A = any, Req = any> implements Output<A, Req> {
|
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
public bind(id: string): any {
|
|
116
|
+
// `set`/`get` store keys verbatim, so canonicalize here (the caller's job).
|
|
117
|
+
const key = sanitizeKey(id);
|
|
115
118
|
return RuntimeContext.pipe(
|
|
116
119
|
Effect.flatMap((ctx) =>
|
|
117
|
-
Effect.map(ctx.set(
|
|
120
|
+
Effect.map(ctx.set(key, this), (k) => ctx.get<A>(k)),
|
|
118
121
|
),
|
|
119
122
|
);
|
|
120
123
|
}
|
|
@@ -590,6 +593,9 @@ export const evaluate: <A, Req = never>(
|
|
|
590
593
|
return yield* Effect.all(expr.map((item) => evaluate(item, upstream)));
|
|
591
594
|
} else if (Redacted.isRedacted(expr)) {
|
|
592
595
|
return expr;
|
|
596
|
+
} else if (Duration.isDuration(expr)) {
|
|
597
|
+
// Opaque value — see resolveInput in Plan.ts for rationale.
|
|
598
|
+
return expr;
|
|
593
599
|
} else if (typeof expr === "object" && expr !== null) {
|
|
594
600
|
return Object.fromEntries(
|
|
595
601
|
yield* Effect.all(
|
package/src/Phase.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import * as Config from "effect/Config";
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
3
|
|
|
4
|
+
export type AlchemyPhase = "plan" | "runtime";
|
|
5
|
+
|
|
4
6
|
export const ALCHEMY_PHASE = Config.string("ALCHEMY_PHASE").pipe(
|
|
5
7
|
Config.withDefault("plan"),
|
|
8
|
+
Config.mapOrFail((value) => {
|
|
9
|
+
if (value !== "plan" && value !== "runtime") {
|
|
10
|
+
return Effect.die(new Error(`Invalid ALCHEMY_PHASE: ${value}`));
|
|
11
|
+
}
|
|
12
|
+
return Effect.succeed(value as AlchemyPhase);
|
|
13
|
+
}),
|
|
6
14
|
Effect.orDie,
|
|
7
15
|
);
|