@alchemy.run/modal 0.0.0 → 2.0.0-beta.86
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/LICENSE +201 -0
- package/README.md +96 -4
- package/lib/App.d.ts +143 -0
- package/lib/App.d.ts.map +1 -0
- package/lib/App.js +198 -0
- package/lib/App.js.map +1 -0
- package/lib/AuthProvider.d.ts +53 -0
- package/lib/AuthProvider.d.ts.map +1 -0
- package/lib/AuthProvider.js +209 -0
- package/lib/AuthProvider.js.map +1 -0
- package/lib/BindingHttp.d.ts +56 -0
- package/lib/BindingHttp.d.ts.map +1 -0
- package/lib/BindingHttp.js +50 -0
- package/lib/BindingHttp.js.map +1 -0
- package/lib/Blob.d.ts +34 -0
- package/lib/Blob.d.ts.map +1 -0
- package/lib/Blob.js +59 -0
- package/lib/Blob.js.map +1 -0
- package/lib/Bootstrap.d.ts +8 -0
- package/lib/Bootstrap.d.ts.map +1 -0
- package/lib/Bootstrap.js +26 -0
- package/lib/Bootstrap.js.map +1 -0
- package/lib/Cbor.d.ts +10 -0
- package/lib/Cbor.d.ts.map +1 -0
- package/lib/Cbor.js +177 -0
- package/lib/Cbor.js.map +1 -0
- package/lib/ConnectSandbox.d.ts +64 -0
- package/lib/ConnectSandbox.d.ts.map +1 -0
- package/lib/ConnectSandbox.js +33 -0
- package/lib/ConnectSandbox.js.map +1 -0
- package/lib/Container.d.ts +124 -0
- package/lib/Container.d.ts.map +1 -0
- package/lib/Container.js +1 -0
- package/lib/Container.js.map +1 -0
- package/lib/Contributions.d.ts +7 -0
- package/lib/Contributions.d.ts.map +1 -0
- package/lib/Contributions.js +6 -0
- package/lib/Contributions.js.map +1 -0
- package/lib/CreateDict.d.ts +83 -0
- package/lib/CreateDict.d.ts.map +1 -0
- package/lib/CreateDict.js +3 -0
- package/lib/CreateDict.js.map +1 -0
- package/lib/CreateDictHttp.d.ts +33 -0
- package/lib/CreateDictHttp.d.ts.map +1 -0
- package/lib/CreateDictHttp.js +67 -0
- package/lib/CreateDictHttp.js.map +1 -0
- package/lib/CreateImage.d.ts +98 -0
- package/lib/CreateImage.d.ts.map +1 -0
- package/lib/CreateImage.js +3 -0
- package/lib/CreateImage.js.map +1 -0
- package/lib/CreateImageHttp.d.ts +51 -0
- package/lib/CreateImageHttp.d.ts.map +1 -0
- package/lib/CreateImageHttp.js +87 -0
- package/lib/CreateImageHttp.js.map +1 -0
- package/lib/CreateQueue.d.ts +83 -0
- package/lib/CreateQueue.d.ts.map +1 -0
- package/lib/CreateQueue.js +3 -0
- package/lib/CreateQueue.js.map +1 -0
- package/lib/CreateQueueHttp.d.ts +31 -0
- package/lib/CreateQueueHttp.d.ts.map +1 -0
- package/lib/CreateQueueHttp.js +67 -0
- package/lib/CreateQueueHttp.js.map +1 -0
- package/lib/CreateSandbox.d.ts +186 -0
- package/lib/CreateSandbox.d.ts.map +1 -0
- package/lib/CreateSandbox.js +3 -0
- package/lib/CreateSandbox.js.map +1 -0
- package/lib/CreateSandboxHttp.d.ts +17 -0
- package/lib/CreateSandboxHttp.d.ts.map +1 -0
- package/lib/CreateSandboxHttp.js +117 -0
- package/lib/CreateSandboxHttp.js.map +1 -0
- package/lib/CreateSecret.d.ts +95 -0
- package/lib/CreateSecret.d.ts.map +1 -0
- package/lib/CreateSecret.js +3 -0
- package/lib/CreateSecret.js.map +1 -0
- package/lib/CreateSecretHttp.d.ts +24 -0
- package/lib/CreateSecretHttp.d.ts.map +1 -0
- package/lib/CreateSecretHttp.js +60 -0
- package/lib/CreateSecretHttp.js.map +1 -0
- package/lib/CreateVolume.d.ts +84 -0
- package/lib/CreateVolume.d.ts.map +1 -0
- package/lib/CreateVolume.js +3 -0
- package/lib/CreateVolume.js.map +1 -0
- package/lib/CreateVolumeHttp.d.ts +32 -0
- package/lib/CreateVolumeHttp.d.ts.map +1 -0
- package/lib/CreateVolumeHttp.js +69 -0
- package/lib/CreateVolumeHttp.js.map +1 -0
- package/lib/Credentials.d.ts +32 -0
- package/lib/Credentials.d.ts.map +1 -0
- package/lib/Credentials.js +44 -0
- package/lib/Credentials.js.map +1 -0
- package/lib/Dict.d.ts +147 -0
- package/lib/Dict.d.ts.map +1 -0
- package/lib/Dict.js +175 -0
- package/lib/Dict.js.map +1 -0
- package/lib/DictClient.d.ts +55 -0
- package/lib/DictClient.d.ts.map +1 -0
- package/lib/DictClient.js +89 -0
- package/lib/DictClient.js.map +1 -0
- package/lib/Domain.d.ts +86 -0
- package/lib/Domain.d.ts.map +1 -0
- package/lib/Domain.js +113 -0
- package/lib/Domain.js.map +1 -0
- package/lib/Endpoint.d.ts +181 -0
- package/lib/Endpoint.d.ts.map +1 -0
- package/lib/Endpoint.js +283 -0
- package/lib/Endpoint.js.map +1 -0
- package/lib/Environment.d.ts +174 -0
- package/lib/Environment.d.ts.map +1 -0
- package/lib/Environment.js +244 -0
- package/lib/Environment.js.map +1 -0
- package/lib/FetchServer.d.ts +105 -0
- package/lib/FetchServer.d.ts.map +1 -0
- package/lib/FetchServer.js +3 -0
- package/lib/FetchServer.js.map +1 -0
- package/lib/FetchServerHttp.d.ts +21 -0
- package/lib/FetchServerHttp.d.ts.map +1 -0
- package/lib/FetchServerHttp.js +84 -0
- package/lib/FetchServerHttp.js.map +1 -0
- package/lib/Function.d.ts +236 -0
- package/lib/Function.d.ts.map +1 -0
- package/lib/Function.js +273 -0
- package/lib/Function.js.map +1 -0
- package/lib/FunctionAutoscaler.d.ts +99 -0
- package/lib/FunctionAutoscaler.d.ts.map +1 -0
- package/lib/FunctionAutoscaler.js +136 -0
- package/lib/FunctionAutoscaler.js.map +1 -0
- package/lib/FunctionTarget.d.ts +61 -0
- package/lib/FunctionTarget.d.ts.map +1 -0
- package/lib/FunctionTarget.js +136 -0
- package/lib/FunctionTarget.js.map +1 -0
- package/lib/Image.d.ts +159 -0
- package/lib/Image.d.ts.map +1 -0
- package/lib/Image.js +203 -0
- package/lib/Image.js.map +1 -0
- package/lib/ImageBuild.d.ts +108 -0
- package/lib/ImageBuild.d.ts.map +1 -0
- package/lib/ImageBuild.js +157 -0
- package/lib/ImageBuild.js.map +1 -0
- package/lib/ImagePlan.d.ts +31 -0
- package/lib/ImagePlan.d.ts.map +1 -0
- package/lib/ImagePlan.js +70 -0
- package/lib/ImagePlan.js.map +1 -0
- package/lib/InferEnv.d.ts +26 -0
- package/lib/InferEnv.d.ts.map +1 -0
- package/lib/InferEnv.js +1 -0
- package/lib/InferEnv.js.map +1 -0
- package/lib/InvokeFunction.d.ts +186 -0
- package/lib/InvokeFunction.d.ts.map +1 -0
- package/lib/InvokeFunction.js +10 -0
- package/lib/InvokeFunction.js.map +1 -0
- package/lib/InvokeFunctionHttp.d.ts +39 -0
- package/lib/InvokeFunctionHttp.d.ts.map +1 -0
- package/lib/InvokeFunctionHttp.js +210 -0
- package/lib/InvokeFunctionHttp.js.map +1 -0
- package/lib/ModalBindings.d.ts +138 -0
- package/lib/ModalBindings.d.ts.map +1 -0
- package/lib/ModalBindings.js +223 -0
- package/lib/ModalBindings.js.map +1 -0
- package/lib/MountBucket.d.ts +80 -0
- package/lib/MountBucket.d.ts.map +1 -0
- package/lib/MountBucket.js +44 -0
- package/lib/MountBucket.js.map +1 -0
- package/lib/MountVolume.d.ts +77 -0
- package/lib/MountVolume.d.ts.map +1 -0
- package/lib/MountVolume.js +41 -0
- package/lib/MountVolume.js.map +1 -0
- package/lib/Mounts.d.ts +134 -0
- package/lib/Mounts.d.ts.map +1 -0
- package/lib/Mounts.js +87 -0
- package/lib/Mounts.js.map +1 -0
- package/lib/PersistentSandbox.d.ts +75 -0
- package/lib/PersistentSandbox.d.ts.map +1 -0
- package/lib/PersistentSandbox.js +93 -0
- package/lib/PersistentSandbox.js.map +1 -0
- package/lib/Providers.d.ts +23 -0
- package/lib/Providers.d.ts.map +1 -0
- package/lib/Providers.js +64 -0
- package/lib/Providers.js.map +1 -0
- package/lib/Proxy.d.ts +94 -0
- package/lib/Proxy.d.ts.map +1 -0
- package/lib/Proxy.js +132 -0
- package/lib/Proxy.js.map +1 -0
- package/lib/Queue.d.ts +147 -0
- package/lib/Queue.d.ts.map +1 -0
- package/lib/Queue.js +177 -0
- package/lib/Queue.js.map +1 -0
- package/lib/QueueClient.d.ts +64 -0
- package/lib/QueueClient.d.ts.map +1 -0
- package/lib/QueueClient.js +73 -0
- package/lib/QueueClient.js.map +1 -0
- package/lib/ReadApp.d.ts +85 -0
- package/lib/ReadApp.d.ts.map +1 -0
- package/lib/ReadApp.js +3 -0
- package/lib/ReadApp.js.map +1 -0
- package/lib/ReadAppHttp.d.ts +26 -0
- package/lib/ReadAppHttp.d.ts.map +1 -0
- package/lib/ReadAppHttp.js +106 -0
- package/lib/ReadAppHttp.js.map +1 -0
- package/lib/ReadDict.d.ts +39 -0
- package/lib/ReadDict.d.ts.map +1 -0
- package/lib/ReadDict.js +3 -0
- package/lib/ReadDict.js.map +1 -0
- package/lib/ReadDictHttp.d.ts +12 -0
- package/lib/ReadDictHttp.d.ts.map +1 -0
- package/lib/ReadDictHttp.js +23 -0
- package/lib/ReadDictHttp.js.map +1 -0
- package/lib/ReadFunction.d.ts +73 -0
- package/lib/ReadFunction.d.ts.map +1 -0
- package/lib/ReadFunction.js +3 -0
- package/lib/ReadFunction.js.map +1 -0
- package/lib/ReadFunctionHttp.d.ts +25 -0
- package/lib/ReadFunctionHttp.d.ts.map +1 -0
- package/lib/ReadFunctionHttp.js +63 -0
- package/lib/ReadFunctionHttp.js.map +1 -0
- package/lib/ReadQueue.d.ts +39 -0
- package/lib/ReadQueue.d.ts.map +1 -0
- package/lib/ReadQueue.js +3 -0
- package/lib/ReadQueue.js.map +1 -0
- package/lib/ReadQueueHttp.d.ts +12 -0
- package/lib/ReadQueueHttp.d.ts.map +1 -0
- package/lib/ReadQueueHttp.js +23 -0
- package/lib/ReadQueueHttp.js.map +1 -0
- package/lib/ReadServer.d.ts +72 -0
- package/lib/ReadServer.d.ts.map +1 -0
- package/lib/ReadServer.js +3 -0
- package/lib/ReadServer.js.map +1 -0
- package/lib/ReadServerHttp.d.ts +25 -0
- package/lib/ReadServerHttp.d.ts.map +1 -0
- package/lib/ReadServerHttp.js +70 -0
- package/lib/ReadServerHttp.js.map +1 -0
- package/lib/ReadVolume.d.ts +40 -0
- package/lib/ReadVolume.d.ts.map +1 -0
- package/lib/ReadVolume.js +3 -0
- package/lib/ReadVolume.js.map +1 -0
- package/lib/ReadVolumeHttp.d.ts +12 -0
- package/lib/ReadVolumeHttp.d.ts.map +1 -0
- package/lib/ReadVolumeHttp.js +24 -0
- package/lib/ReadVolumeHttp.js.map +1 -0
- package/lib/ReadWriteDict.d.ts +39 -0
- package/lib/ReadWriteDict.d.ts.map +1 -0
- package/lib/ReadWriteDict.js +3 -0
- package/lib/ReadWriteDict.js.map +1 -0
- package/lib/ReadWriteDictHttp.d.ts +12 -0
- package/lib/ReadWriteDictHttp.d.ts.map +1 -0
- package/lib/ReadWriteDictHttp.js +23 -0
- package/lib/ReadWriteDictHttp.js.map +1 -0
- package/lib/ReadWriteQueue.d.ts +40 -0
- package/lib/ReadWriteQueue.d.ts.map +1 -0
- package/lib/ReadWriteQueue.js +3 -0
- package/lib/ReadWriteQueue.js.map +1 -0
- package/lib/ReadWriteQueueHttp.d.ts +12 -0
- package/lib/ReadWriteQueueHttp.d.ts.map +1 -0
- package/lib/ReadWriteQueueHttp.js +23 -0
- package/lib/ReadWriteQueueHttp.js.map +1 -0
- package/lib/ReadWriteVolume.d.ts +40 -0
- package/lib/ReadWriteVolume.d.ts.map +1 -0
- package/lib/ReadWriteVolume.js +3 -0
- package/lib/ReadWriteVolume.js.map +1 -0
- package/lib/ReadWriteVolumeHttp.d.ts +12 -0
- package/lib/ReadWriteVolumeHttp.d.ts.map +1 -0
- package/lib/ReadWriteVolumeHttp.js +24 -0
- package/lib/ReadWriteVolumeHttp.js.map +1 -0
- package/lib/RuntimeOwner.d.ts +39 -0
- package/lib/RuntimeOwner.d.ts.map +1 -0
- package/lib/RuntimeOwner.js +85 -0
- package/lib/RuntimeOwner.js.map +1 -0
- package/lib/Sandbox.d.ts +215 -0
- package/lib/Sandbox.d.ts.map +1 -0
- package/lib/Sandbox.js +278 -0
- package/lib/Sandbox.js.map +1 -0
- package/lib/SandboxClient.d.ts +748 -0
- package/lib/SandboxClient.d.ts.map +1 -0
- package/lib/SandboxClient.js +710 -0
- package/lib/SandboxClient.js.map +1 -0
- package/lib/ScaleFunction.d.ts +54 -0
- package/lib/ScaleFunction.d.ts.map +1 -0
- package/lib/ScaleFunction.js +3 -0
- package/lib/ScaleFunction.js.map +1 -0
- package/lib/ScaleFunctionHttp.d.ts +21 -0
- package/lib/ScaleFunctionHttp.d.ts.map +1 -0
- package/lib/ScaleFunctionHttp.js +39 -0
- package/lib/ScaleFunctionHttp.js.map +1 -0
- package/lib/Secret.d.ts +170 -0
- package/lib/Secret.d.ts.map +1 -0
- package/lib/Secret.js +196 -0
- package/lib/Secret.js.map +1 -0
- package/lib/Server.d.ts +155 -0
- package/lib/Server.d.ts.map +1 -0
- package/lib/Server.js +184 -0
- package/lib/Server.js.map +1 -0
- package/lib/ServiceUser.d.ts +139 -0
- package/lib/ServiceUser.d.ts.map +1 -0
- package/lib/ServiceUser.js +210 -0
- package/lib/ServiceUser.js.map +1 -0
- package/lib/Volume.d.ts +170 -0
- package/lib/Volume.d.ts.map +1 -0
- package/lib/Volume.js +220 -0
- package/lib/Volume.js.map +1 -0
- package/lib/VolumeClient.d.ts +53 -0
- package/lib/VolumeClient.d.ts.map +1 -0
- package/lib/VolumeClient.js +22 -0
- package/lib/VolumeClient.js.map +1 -0
- package/lib/VolumeFiles.d.ts +94 -0
- package/lib/VolumeFiles.d.ts.map +1 -0
- package/lib/VolumeFiles.js +139 -0
- package/lib/VolumeFiles.js.map +1 -0
- package/lib/WebhookToken.d.ts +102 -0
- package/lib/WebhookToken.d.ts.map +1 -0
- package/lib/WebhookToken.js +176 -0
- package/lib/WebhookToken.js.map +1 -0
- package/lib/WorkspaceSettings.d.ts +70 -0
- package/lib/WorkspaceSettings.d.ts.map +1 -0
- package/lib/WorkspaceSettings.js +105 -0
- package/lib/WorkspaceSettings.js.map +1 -0
- package/lib/WriteApp.d.ts +38 -0
- package/lib/WriteApp.d.ts.map +1 -0
- package/lib/WriteApp.js +3 -0
- package/lib/WriteApp.js.map +1 -0
- package/lib/WriteAppHttp.d.ts +23 -0
- package/lib/WriteAppHttp.d.ts.map +1 -0
- package/lib/WriteAppHttp.js +36 -0
- package/lib/WriteAppHttp.js.map +1 -0
- package/lib/WriteDict.d.ts +39 -0
- package/lib/WriteDict.d.ts.map +1 -0
- package/lib/WriteDict.js +3 -0
- package/lib/WriteDict.js.map +1 -0
- package/lib/WriteDictHttp.d.ts +12 -0
- package/lib/WriteDictHttp.d.ts.map +1 -0
- package/lib/WriteDictHttp.js +23 -0
- package/lib/WriteDictHttp.js.map +1 -0
- package/lib/WriteQueue.d.ts +39 -0
- package/lib/WriteQueue.d.ts.map +1 -0
- package/lib/WriteQueue.js +3 -0
- package/lib/WriteQueue.js.map +1 -0
- package/lib/WriteQueueHttp.d.ts +12 -0
- package/lib/WriteQueueHttp.d.ts.map +1 -0
- package/lib/WriteQueueHttp.js +23 -0
- package/lib/WriteQueueHttp.js.map +1 -0
- package/lib/WriteSecret.d.ts +53 -0
- package/lib/WriteSecret.d.ts.map +1 -0
- package/lib/WriteSecret.js +3 -0
- package/lib/WriteSecret.js.map +1 -0
- package/lib/WriteSecretHttp.d.ts +23 -0
- package/lib/WriteSecretHttp.d.ts.map +1 -0
- package/lib/WriteSecretHttp.js +44 -0
- package/lib/WriteSecretHttp.js.map +1 -0
- package/lib/WriteVolume.d.ts +39 -0
- package/lib/WriteVolume.d.ts.map +1 -0
- package/lib/WriteVolume.js +3 -0
- package/lib/WriteVolume.js.map +1 -0
- package/lib/WriteVolumeHttp.d.ts +12 -0
- package/lib/WriteVolumeHttp.d.ts.map +1 -0
- package/lib/WriteVolumeHttp.js +24 -0
- package/lib/WriteVolumeHttp.js.map +1 -0
- package/lib/index.d.ts +80 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +78 -0
- package/lib/index.js.map +1 -0
- package/lib/internal/Declared.d.ts +29 -0
- package/lib/internal/Declared.d.ts.map +1 -0
- package/lib/internal/Declared.js +31 -0
- package/lib/internal/Declared.js.map +1 -0
- package/lib/internal/Deploy.d.ts +110 -0
- package/lib/internal/Deploy.d.ts.map +1 -0
- package/lib/internal/Deploy.js +230 -0
- package/lib/internal/Deploy.js.map +1 -0
- package/lib/internal/Entrypoint.d.ts +52 -0
- package/lib/internal/Entrypoint.d.ts.map +1 -0
- package/lib/internal/Entrypoint.js +193 -0
- package/lib/internal/Entrypoint.js.map +1 -0
- package/lib/internal/Rpc.d.ts +17 -0
- package/lib/internal/Rpc.d.ts.map +1 -0
- package/lib/internal/Rpc.js +49 -0
- package/lib/internal/Rpc.js.map +1 -0
- package/lib/internal/RpcAuth.d.ts +41 -0
- package/lib/internal/RpcAuth.d.ts.map +1 -0
- package/lib/internal/RpcAuth.js +100 -0
- package/lib/internal/RpcAuth.js.map +1 -0
- package/lib/internal/Runtime.d.ts +127 -0
- package/lib/internal/Runtime.d.ts.map +1 -0
- package/lib/internal/Runtime.js +246 -0
- package/lib/internal/Runtime.js.map +1 -0
- package/lib/internal/Tags.d.ts +19 -0
- package/lib/internal/Tags.d.ts.map +1 -0
- package/lib/internal/Tags.js +33 -0
- package/lib/internal/Tags.js.map +1 -0
- package/lib/internal/TcpConnect.d.ts +12 -0
- package/lib/internal/TcpConnect.d.ts.map +1 -0
- package/lib/internal/TcpConnect.js +46 -0
- package/lib/internal/TcpConnect.js.map +1 -0
- package/lib/internal/Transport.d.ts +13 -0
- package/lib/internal/Transport.d.ts.map +1 -0
- package/lib/internal/Transport.js +16 -0
- package/lib/internal/Transport.js.map +1 -0
- package/lib/internal.d.ts +71 -0
- package/lib/internal.d.ts.map +1 -0
- package/lib/internal.js +102 -0
- package/lib/internal.js.map +1 -0
- package/package.json +59 -3
- package/src/App.ts +262 -0
- package/src/AuthProvider.ts +295 -0
- package/src/BindingHttp.ts +112 -0
- package/src/Blob.ts +71 -0
- package/src/Bootstrap.ts +52 -0
- package/src/Cbor.ts +158 -0
- package/src/ConnectSandbox.ts +99 -0
- package/src/Container.ts +121 -0
- package/src/Contributions.ts +9 -0
- package/src/CreateDict.ts +95 -0
- package/src/CreateDictHttp.ts +91 -0
- package/src/CreateImage.ts +105 -0
- package/src/CreateImageHttp.ts +117 -0
- package/src/CreateQueue.ts +95 -0
- package/src/CreateQueueHttp.ts +91 -0
- package/src/CreateSandbox.ts +228 -0
- package/src/CreateSandboxHttp.ts +160 -0
- package/src/CreateSecret.ts +109 -0
- package/src/CreateSecretHttp.ts +83 -0
- package/src/CreateVolume.ts +96 -0
- package/src/CreateVolumeHttp.ts +93 -0
- package/src/Credentials.ts +74 -0
- package/src/Dict.ts +245 -0
- package/src/DictClient.ts +166 -0
- package/src/Domain.ts +147 -0
- package/src/Endpoint.ts +406 -0
- package/src/Environment.ts +373 -0
- package/src/FetchServer.ts +126 -0
- package/src/FetchServerHttp.ts +110 -0
- package/src/Function.ts +397 -0
- package/src/FunctionAutoscaler.ts +210 -0
- package/src/FunctionTarget.ts +181 -0
- package/src/Image.ts +281 -0
- package/src/ImageBuild.ts +228 -0
- package/src/ImagePlan.ts +78 -0
- package/src/InferEnv.ts +27 -0
- package/src/InvokeFunction.ts +211 -0
- package/src/InvokeFunctionHttp.ts +316 -0
- package/src/ModalBindings.ts +310 -0
- package/src/MountBucket.ts +137 -0
- package/src/MountVolume.ts +113 -0
- package/src/Mounts.ts +230 -0
- package/src/PersistentSandbox.ts +142 -0
- package/src/Providers.ts +100 -0
- package/src/Proxy.ts +191 -0
- package/src/Queue.ts +258 -0
- package/src/QueueClient.ts +149 -0
- package/src/ReadApp.ts +101 -0
- package/src/ReadAppHttp.ts +142 -0
- package/src/ReadDict.ts +44 -0
- package/src/ReadDictHttp.ts +27 -0
- package/src/ReadFunction.ts +107 -0
- package/src/ReadFunctionHttp.ts +91 -0
- package/src/ReadQueue.ts +44 -0
- package/src/ReadQueueHttp.ts +27 -0
- package/src/ReadServer.ts +98 -0
- package/src/ReadServerHttp.ts +101 -0
- package/src/ReadVolume.ts +45 -0
- package/src/ReadVolumeHttp.ts +28 -0
- package/src/ReadWriteDict.ts +44 -0
- package/src/ReadWriteDictHttp.ts +27 -0
- package/src/ReadWriteQueue.ts +45 -0
- package/src/ReadWriteQueueHttp.ts +27 -0
- package/src/ReadWriteVolume.ts +45 -0
- package/src/ReadWriteVolumeHttp.ts +28 -0
- package/src/RuntimeOwner.ts +111 -0
- package/src/Sandbox.ts +402 -0
- package/src/SandboxClient.ts +1404 -0
- package/src/ScaleFunction.ts +70 -0
- package/src/ScaleFunctionHttp.ts +54 -0
- package/src/Secret.ts +296 -0
- package/src/Server.ts +285 -0
- package/src/ServiceUser.ts +295 -0
- package/src/Volume.ts +320 -0
- package/src/VolumeClient.ts +108 -0
- package/src/VolumeFiles.ts +194 -0
- package/src/WebhookToken.ts +230 -0
- package/src/WorkspaceSettings.ts +160 -0
- package/src/WriteApp.ts +43 -0
- package/src/WriteAppHttp.ts +51 -0
- package/src/WriteDict.ts +44 -0
- package/src/WriteDictHttp.ts +27 -0
- package/src/WriteQueue.ts +44 -0
- package/src/WriteQueueHttp.ts +27 -0
- package/src/WriteSecret.ts +60 -0
- package/src/WriteSecretHttp.ts +56 -0
- package/src/WriteVolume.ts +44 -0
- package/src/WriteVolumeHttp.ts +28 -0
- package/src/globals.d.ts +2 -0
- package/src/index.ts +85 -0
- package/src/internal/Declared.ts +80 -0
- package/src/internal/Deploy.ts +309 -0
- package/src/internal/Entrypoint.ts +198 -0
- package/src/internal/Rpc.ts +59 -0
- package/src/internal/RpcAuth.ts +132 -0
- package/src/internal/Runtime.ts +386 -0
- package/src/internal/Tags.ts +44 -0
- package/src/internal/TcpConnect.ts +78 -0
- package/src/internal/Transport.ts +25 -0
- package/src/internal.ts +147 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { GrpcTransport } from "@distilled.cloud/core/grpc-transport";
|
|
2
|
+
import { withAuthToken } from "@distilled.cloud/modal/AuthToken";
|
|
3
|
+
import {
|
|
4
|
+
containerSocket,
|
|
5
|
+
Credentials,
|
|
6
|
+
CredentialsFromEnv,
|
|
7
|
+
credentials,
|
|
8
|
+
fromContainer,
|
|
9
|
+
streamTaskCommandRouter,
|
|
10
|
+
withTaskCommandRouter,
|
|
11
|
+
} from "@distilled.cloud/modal/Credentials";
|
|
12
|
+
import { orDieCredentialsUnavailable } from "alchemy/Auth/Resolve";
|
|
13
|
+
import * as Binding from "alchemy/Binding";
|
|
14
|
+
import type { Input } from "alchemy/Input";
|
|
15
|
+
import * as Output from "alchemy/Output";
|
|
16
|
+
import { CurrentRuntimeContext } from "alchemy/RuntimeContext";
|
|
17
|
+
import * as Context from "effect/Context";
|
|
18
|
+
import * as Effect from "effect/Effect";
|
|
19
|
+
import * as FetchHttpClient from "effect/http/FetchHttpClient";
|
|
20
|
+
import * as HttpClient from "effect/http/HttpClient";
|
|
21
|
+
import * as Layer from "effect/Layer";
|
|
22
|
+
import * as Option from "effect/Option";
|
|
23
|
+
import * as Redacted from "effect/Redacted";
|
|
24
|
+
import type * as Stream from "effect/Stream";
|
|
25
|
+
import { withAuthTokens } from "./Credentials.ts";
|
|
26
|
+
import type { OperationServices } from "./internal.ts";
|
|
27
|
+
import { ModalTransport } from "./internal/Transport.ts";
|
|
28
|
+
import { ServiceUser } from "./ServiceUser.ts";
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* How a Modal binding reaches Modal from its host.
|
|
32
|
+
*
|
|
33
|
+
* Modal grants access per environment, as a `viewer` or a `contributor`. So:
|
|
34
|
+
*
|
|
35
|
+
* - a Modal Function or Server: nothing is bound. It calls Modal as its own
|
|
36
|
+
* container, over the API socket Modal gives every container
|
|
37
|
+
* (`fromContainer`), the way Modal's Python client does there. No
|
|
38
|
+
* credential is stored. A host with `restrictModalAccess` has no such
|
|
39
|
+
* access, so it gets a service user like any other host;
|
|
40
|
+
* - any other host (a Cloudflare Worker, a Lambda, a Modal Sandbox):
|
|
41
|
+
* {@link Bind} creates a scoped `Modal.ServiceUser` for the
|
|
42
|
+
* host (`<host>ModalIdentity`), grants it the role each binding asks for
|
|
43
|
+
* on the bound resource's environment, and binds its token pair into the
|
|
44
|
+
* host's env (`MODAL_TOKEN_ID`, and `MODAL_TOKEN_SECRET` kept `Redacted`);
|
|
45
|
+
* - no host (a script or a deploy-time Action): nothing is bound, and calls
|
|
46
|
+
* use the deployer's credentials.
|
|
47
|
+
*
|
|
48
|
+
* Modal's Starter plan has no service users. There, provide
|
|
49
|
+
* {@link DeployerHostIdentity} to bind the deployer's own token pair into
|
|
50
|
+
* each host instead: hosts then act with the deployer's workspace-wide
|
|
51
|
+
* access, not the roles their bindings ask for.
|
|
52
|
+
*
|
|
53
|
+
* Import it as a namespace. A binding resolves its operations with
|
|
54
|
+
* {@link withCredentials} and gets its `bind` from {@link Bind} when its layer
|
|
55
|
+
* is built, then binds behind its own `__ALCHEMY_RUNTIME__` guard:
|
|
56
|
+
*
|
|
57
|
+
* ```ts
|
|
58
|
+
* Effect.gen(function* () {
|
|
59
|
+
* const put = yield* ModalBindings.withCredentials(modalQueue.putQueue);
|
|
60
|
+
* const bind = yield* ModalBindings.Bind;
|
|
61
|
+
* return Effect.fn(function* (queue: Queue) {
|
|
62
|
+
* if (!globalThis.__ALCHEMY_RUNTIME__) {
|
|
63
|
+
* yield* bind`Modal.WriteQueue(${queue})`({
|
|
64
|
+
* roles: [{ environment: queue.environment, role: "contributor" }],
|
|
65
|
+
* });
|
|
66
|
+
* }
|
|
67
|
+
* const queueId = yield* queue.queueId;
|
|
68
|
+
* return (value) => put({ queueId: yield* queueId, values: [...] });
|
|
69
|
+
* });
|
|
70
|
+
* })
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export const TOKEN_ENV = {
|
|
74
|
+
id: "MODAL_TOKEN_ID",
|
|
75
|
+
secret: "MODAL_TOKEN_SECRET",
|
|
76
|
+
// Not MODAL_SERVER_URL: inside a Modal container, Modal sets that to the
|
|
77
|
+
// container's own socket (`unix:/run/modal.sock`), shadowing ours.
|
|
78
|
+
serverUrl: "ALCHEMY_MODAL_SERVER_URL",
|
|
79
|
+
} as const;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The identity {@link Bind} gives a binding's host:
|
|
83
|
+
*
|
|
84
|
+
* - `"service-user"`: a scoped `Modal.ServiceUser` per host with only the
|
|
85
|
+
* roles its bindings ask for (needs Modal's Team or Enterprise plan);
|
|
86
|
+
* - `"deployer"`: the deployer's own token pair, with its workspace-wide
|
|
87
|
+
* access (for the Starter plan, which has no service users).
|
|
88
|
+
*
|
|
89
|
+
* Set it with {@link DeployerHostIdentity}.
|
|
90
|
+
*/
|
|
91
|
+
export const HostIdentity = Context.Reference<"service-user" | "deployer">("Modal/HostIdentity", {
|
|
92
|
+
defaultValue: () => "service-user",
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Bind the deployer's own Modal token into binding hosts instead of a
|
|
97
|
+
* scoped service user per host. Use it on Modal's Starter plan, which has
|
|
98
|
+
* no service users; hosts then have the deployer's workspace-wide access.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* export default Alchemy.Stack(
|
|
103
|
+
* "App",
|
|
104
|
+
* { providers: Layer.mergeAll(Cloudflare.providers(), Modal.providers(), Modal.DeployerHostIdentity) },
|
|
105
|
+
* Effect.gen(function* () { ... }),
|
|
106
|
+
* );
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export const DeployerHostIdentity: Layer.Layer<never> = Layer.succeed(HostIdentity, "deployer");
|
|
110
|
+
|
|
111
|
+
/** A role a binding needs in one environment. */
|
|
112
|
+
export interface EnvironmentGrant {
|
|
113
|
+
/** The environment's name; `undefined` is the workspace default. */
|
|
114
|
+
readonly environment: Input<string | undefined>;
|
|
115
|
+
readonly role: "viewer" | "contributor";
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** What a Modal binding attaches to its host. */
|
|
119
|
+
export interface HostBinding {
|
|
120
|
+
/** Environment roles the host's identity needs. */
|
|
121
|
+
readonly roles?: ReadonlyArray<EnvironmentGrant>;
|
|
122
|
+
/** Env vars the binding reads at runtime. */
|
|
123
|
+
readonly env?: Record<string, unknown>;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** The signature {@link Bind} yields. */
|
|
127
|
+
export type BindHost = (
|
|
128
|
+
label: TemplateStringsArray,
|
|
129
|
+
...args: unknown[]
|
|
130
|
+
) => (data?: HostBinding) => Effect.Effect<void>;
|
|
131
|
+
|
|
132
|
+
type BindTarget = {
|
|
133
|
+
bind: (...args: unknown[]) => (data: unknown) => Effect.Effect<void>;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const labelled = (verb: string, label: TemplateStringsArray): TemplateStringsArray => {
|
|
137
|
+
const strings = [`${verb}(`, `, ${label[0]}`, ...label.slice(1)];
|
|
138
|
+
strings[strings.length - 1] += ")";
|
|
139
|
+
return Object.assign(strings, { raw: strings }) as unknown as TemplateStringsArray;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* The `bind` for a binding's layer: yield it while the layer is built, then
|
|
144
|
+
* call it from the returned function behind a literal
|
|
145
|
+
* `if (!globalThis.__ALCHEMY_RUNTIME__)` so the bundler drops it. On a host it
|
|
146
|
+
* grants `data.roles` to the host's service user and binds that user's token
|
|
147
|
+
* pair (and `data.env`) into the host's env; with no host it does nothing.
|
|
148
|
+
*/
|
|
149
|
+
export const Bind: Effect.Effect<BindHost> = Effect.gen(function* () {
|
|
150
|
+
// Bindings only bind at deploy, so a host bundle captures nothing here
|
|
151
|
+
// and drops the identity resource.
|
|
152
|
+
if (globalThis.__ALCHEMY_RUNTIME__) return () => () => Effect.void;
|
|
153
|
+
const Identity = yield* ServiceUser;
|
|
154
|
+
const identity = yield* HostIdentity;
|
|
155
|
+
const ambient = yield* Effect.serviceOption(Credentials);
|
|
156
|
+
return (label: TemplateStringsArray, ...args: unknown[]) =>
|
|
157
|
+
Effect.fn(function* (data: HostBinding = {}) {
|
|
158
|
+
const host = yield* Binding.Host;
|
|
159
|
+
if (host === undefined) return;
|
|
160
|
+
const runtime = yield* CurrentRuntimeContext;
|
|
161
|
+
if (runtime === undefined) return;
|
|
162
|
+
|
|
163
|
+
// A binding that calls no Modal API (only `env`) needs no identity, and
|
|
164
|
+
// a Modal Function or Server calls as its own container.
|
|
165
|
+
if (data.roles !== undefined && data.roles.length > 0 && !callsAsContainer(host)) {
|
|
166
|
+
// The host talks to the deployer's Modal control plane.
|
|
167
|
+
const resolve = Option.isSome(ambient)
|
|
168
|
+
? ambient.value
|
|
169
|
+
: yield* Credentials.pipe(Effect.provide(CredentialsFromEnv));
|
|
170
|
+
// Binding initialization can't fail; the engine reports this defect as
|
|
171
|
+
// `CredentialsRequired`.
|
|
172
|
+
const creds = yield* resolve.pipe(orDieCredentialsUnavailable("Modal"));
|
|
173
|
+
if (identity === "deployer") {
|
|
174
|
+
yield* runtime.set(TOKEN_ENV.id, creds.tokenId.pipe(Redacted.value, Output.literal));
|
|
175
|
+
yield* runtime.set(TOKEN_ENV.secret, Output.literal(creds.tokenSecret));
|
|
176
|
+
} else {
|
|
177
|
+
const user = yield* Identity(`${host.LogicalId}ModalIdentity`, { scoped: true });
|
|
178
|
+
yield* (user as unknown as BindTarget).bind(
|
|
179
|
+
labelled("Allow", label),
|
|
180
|
+
host,
|
|
181
|
+
...args,
|
|
182
|
+
)({ environments: data.roles });
|
|
183
|
+
yield* runtime.set(TOKEN_ENV.id, user.tokenId);
|
|
184
|
+
yield* runtime.set(TOKEN_ENV.secret, user.tokenSecret);
|
|
185
|
+
}
|
|
186
|
+
yield* runtime.set(TOKEN_ENV.serverUrl, Output.literal(creds.apiBaseUrl));
|
|
187
|
+
}
|
|
188
|
+
for (const [name, value] of Object.entries(data.env ?? {})) {
|
|
189
|
+
yield* runtime.set(name, Output.isOutput(value) ? value : Output.literal(value));
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
/** Host types whose containers call Modal over their own API socket. */
|
|
195
|
+
const CONTAINER_HOSTS = new Set(["Modal.Function", "Modal.Server"]);
|
|
196
|
+
|
|
197
|
+
/** Whether `host` calls Modal as its container instead of with a bound token. */
|
|
198
|
+
const callsAsContainer = (host: { readonly Type?: string; readonly Props?: unknown }) =>
|
|
199
|
+
CONTAINER_HOSTS.has(host.Type ?? "") &&
|
|
200
|
+
!(host.Props as { readonly restrictModalAccess?: boolean } | undefined)?.restrictModalAccess;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* The credentials, HTTP client and gRPC transport distilled operations run
|
|
204
|
+
* with on this host. A resolved operation keeps them as a fallback under its
|
|
205
|
+
* caller's context, so a Worker's own `HttpClient` doesn't displace the
|
|
206
|
+
* transport.
|
|
207
|
+
*/
|
|
208
|
+
const operationContext = Effect.gen(function* () {
|
|
209
|
+
const runtime = yield* CurrentRuntimeContext;
|
|
210
|
+
if (globalThis.__ALCHEMY_RUNTIME__ && runtime !== undefined) {
|
|
211
|
+
const tokenId = yield* runtime.get<string>(TOKEN_ENV.id);
|
|
212
|
+
const tokenSecret = yield* runtime.get<string | Redacted.Redacted<string>>(TOKEN_ENV.secret);
|
|
213
|
+
if (tokenId !== undefined && tokenSecret !== undefined) {
|
|
214
|
+
const serverUrl = yield* runtime.get<string>(TOKEN_ENV.serverUrl);
|
|
215
|
+
return yield* Layer.build(
|
|
216
|
+
Layer.mergeAll(
|
|
217
|
+
withAuthTokens(
|
|
218
|
+
credentials({
|
|
219
|
+
tokenId: Redacted.make(tokenId),
|
|
220
|
+
tokenSecret: Redacted.isRedacted(tokenSecret)
|
|
221
|
+
? tokenSecret
|
|
222
|
+
: Redacted.make(tokenSecret),
|
|
223
|
+
apiBaseUrl: serverUrl,
|
|
224
|
+
}),
|
|
225
|
+
),
|
|
226
|
+
ModalTransport,
|
|
227
|
+
),
|
|
228
|
+
).pipe(Effect.scoped);
|
|
229
|
+
}
|
|
230
|
+
// A Modal Function or Server: call as the container (see `Bind`).
|
|
231
|
+
const socket = yield* containerSocket;
|
|
232
|
+
if (socket !== undefined) {
|
|
233
|
+
return yield* Layer.build(
|
|
234
|
+
Layer.mergeAll(
|
|
235
|
+
withAuthToken.pipe(Layer.provide(Layer.mergeAll(fromContainer, FetchHttpClient.layer))),
|
|
236
|
+
fromContainer,
|
|
237
|
+
FetchHttpClient.layer,
|
|
238
|
+
),
|
|
239
|
+
).pipe(Effect.orDie, Effect.scoped);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// No bound identity (deploy, scripts, Actions): the ambient Modal
|
|
243
|
+
// credentials, falling back to `MODAL_TOKEN_ID` / `MODAL_TOKEN_SECRET`.
|
|
244
|
+
const ambientCredentials = yield* Effect.serviceOption(Credentials);
|
|
245
|
+
const ambientHttp = yield* Effect.serviceOption(HttpClient.HttpClient);
|
|
246
|
+
const transport = yield* Effect.provide(Effect.service(GrpcTransport), ModalTransport);
|
|
247
|
+
return Context.make(
|
|
248
|
+
Credentials,
|
|
249
|
+
Option.isSome(ambientCredentials)
|
|
250
|
+
? ambientCredentials.value
|
|
251
|
+
: yield* Credentials.pipe(Effect.provide(withAuthTokens(CredentialsFromEnv))),
|
|
252
|
+
).pipe(
|
|
253
|
+
Context.add(
|
|
254
|
+
HttpClient.HttpClient,
|
|
255
|
+
Option.isSome(ambientHttp)
|
|
256
|
+
? ambientHttp.value
|
|
257
|
+
: yield* HttpClient.HttpClient.pipe(Effect.provide(ModalTransport)),
|
|
258
|
+
),
|
|
259
|
+
Context.add(GrpcTransport, transport),
|
|
260
|
+
);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Resolve a distilled operation (or several, with `Effect.all`) once when
|
|
265
|
+
* the binding's layer is built: with the token pair {@link Bind} bound into
|
|
266
|
+
* the host, or the deployer's credentials when there is none.
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```ts
|
|
270
|
+
* const ops = yield* ModalBindings.withCredentials(
|
|
271
|
+
* operations({ getFile: volume.volumeGetFile2, putFiles: volume.volumePutFiles2 }),
|
|
272
|
+
* );
|
|
273
|
+
* ```
|
|
274
|
+
*/
|
|
275
|
+
export const withCredentials: <Op>(
|
|
276
|
+
operation: Effect.Effect<Op, never, OperationServices>,
|
|
277
|
+
) => Effect.Effect<Op> = Effect.fn(function* <Op>(
|
|
278
|
+
operation: Effect.Effect<Op, never, OperationServices>,
|
|
279
|
+
) {
|
|
280
|
+
const context = yield* operationContext;
|
|
281
|
+
return yield* operation.pipe(Effect.provide(context));
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Resolve a task command router operation for one sandbox: the router runs
|
|
286
|
+
* per task, at a URL with its own JWT (from `sandboxGetCommandRouterAccess`).
|
|
287
|
+
* The router credentials are applied on every call, because a resolved
|
|
288
|
+
* operation runs with its caller's `Credentials` (the control plane's) over
|
|
289
|
+
* the ones it captured. `withTaskCommandRouter` also supplies the HTTP/2
|
|
290
|
+
* client the router requires.
|
|
291
|
+
*/
|
|
292
|
+
export const withRouter =
|
|
293
|
+
<I, O, E>(operation: (input: I) => Effect.Effect<O, E, OperationServices>) =>
|
|
294
|
+
(access: RouterAccess): Effect.Effect<(input: I) => Effect.Effect<O, E>> =>
|
|
295
|
+
Effect.succeed((input: I) => operation(input).pipe(withTaskCommandRouter(access)));
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* {@link withRouter} for a server-streaming router operation: its `.stream`,
|
|
299
|
+
* which emits each message as the router sends it.
|
|
300
|
+
*/
|
|
301
|
+
export const streamRouter =
|
|
302
|
+
<I, A, E>(operation: { readonly stream: (input: I) => Stream.Stream<A, E, OperationServices> }) =>
|
|
303
|
+
(access: RouterAccess): Effect.Effect<(input: I) => Stream.Stream<A, E>> =>
|
|
304
|
+
Effect.succeed((input: I) => operation.stream(input).pipe(streamTaskCommandRouter(access)));
|
|
305
|
+
|
|
306
|
+
/** A task's command router: its URL and JWT, from `sandboxGetCommandRouterAccess`. */
|
|
307
|
+
export interface RouterAccess {
|
|
308
|
+
readonly url: string;
|
|
309
|
+
readonly jwt: string;
|
|
310
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import * as Binding from "alchemy/Binding";
|
|
2
|
+
import type * as Output from "alchemy/Output";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Layer from "effect/Layer";
|
|
5
|
+
import {
|
|
6
|
+
type BucketMount,
|
|
7
|
+
type BucketMountOptions,
|
|
8
|
+
type MountedBucket,
|
|
9
|
+
r2Endpoint,
|
|
10
|
+
} from "./Mounts.ts";
|
|
11
|
+
import { MODAL_RUNTIMES, type MountHost } from "./MountVolume.ts";
|
|
12
|
+
import type { Secret } from "./Secret.ts";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A bucket resource of another provider: an AWS S3 Bucket, a Cloudflare R2
|
|
16
|
+
* Bucket, a GCS bucket. Its name (and, for R2, its account endpoint) is
|
|
17
|
+
* read from its attributes.
|
|
18
|
+
*/
|
|
19
|
+
export interface BucketResource {
|
|
20
|
+
readonly Type: string;
|
|
21
|
+
readonly bucketName: Output.Output<string, never>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Options for `Modal.MountBucket`: Modal's cloud bucket mount fields, plus the keys' secret. */
|
|
25
|
+
export interface MountBucketOptions extends BucketMountOptions {
|
|
26
|
+
/**
|
|
27
|
+
* A `Modal.Secret` holding the bucket's keys (`AWS_ACCESS_KEY_ID` /
|
|
28
|
+
* `AWS_SECRET_ACCESS_KEY`, or GCS HMAC keys). Omit it with `oidcAuthRoleArn`.
|
|
29
|
+
*/
|
|
30
|
+
readonly secret?: Secret;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** What `Modal.MountBucket` returns: a mount entry, ready for `mounts`. */
|
|
34
|
+
export type BucketMountRef = BucketMount<
|
|
35
|
+
string | MountedBucket,
|
|
36
|
+
{ readonly secretId: Effect.Effect<string> }
|
|
37
|
+
>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Mount a cloud bucket at `path` with Modal's cloud bucket mounts: a bucket
|
|
41
|
+
* name, or a bucket resource of another provider (an AWS S3 Bucket, a
|
|
42
|
+
* Cloudflare R2 Bucket, whose account endpoint is filled in).
|
|
43
|
+
*
|
|
44
|
+
* - In a `Modal.Function`, `Modal.Server` or `Modal.Sandbox` program, the
|
|
45
|
+
* bucket is mounted into every container the program runs in.
|
|
46
|
+
* - In any other runtime, the binding returns the entry to pass to
|
|
47
|
+
* `sandboxes.create({ mounts })`.
|
|
48
|
+
*
|
|
49
|
+
* Modal reads the bucket with the keys in `secret`, or by assuming
|
|
50
|
+
* `oidcAuthRoleArn` with its OIDC identity.
|
|
51
|
+
*
|
|
52
|
+
* ### Mount an R2 bucket
|
|
53
|
+
* **Example:** A sandbox program reading uploads from Cloudflare R2
|
|
54
|
+
* ```typescript
|
|
55
|
+
* import * as Modal from "@alchemy.run/modal";
|
|
56
|
+
* import * as Effect from "effect/Effect";
|
|
57
|
+
* import * as FileSystem from "effect/FileSystem";
|
|
58
|
+
* import * as HttpServerResponse from "effect/http/HttpServerResponse";
|
|
59
|
+
* import { Coder, R2Keys, Uploads } from "./Storage.ts";
|
|
60
|
+
*
|
|
61
|
+
* export default class Agent extends Modal.Sandbox<Agent>()(
|
|
62
|
+
* "Agent",
|
|
63
|
+
* { main: import.meta.url, app: Coder },
|
|
64
|
+
* Effect.gen(function* () {
|
|
65
|
+
* const uploads = yield* Modal.MountBucket(Uploads, { path: "/uploads", secret: R2Keys });
|
|
66
|
+
* const fs = yield* FileSystem.FileSystem;
|
|
67
|
+
* return {
|
|
68
|
+
* fetch: Effect.gen(function* () {
|
|
69
|
+
* return yield* HttpServerResponse.json(yield* fs.readDirectory(uploads.path));
|
|
70
|
+
* }).pipe(Effect.orDie),
|
|
71
|
+
* };
|
|
72
|
+
* }).pipe(Effect.provide(Modal.MountBucketLive)),
|
|
73
|
+
* ) {}
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* @binding
|
|
77
|
+
* @product Volume
|
|
78
|
+
*/
|
|
79
|
+
export interface MountBucket extends Binding.Service<
|
|
80
|
+
MountBucket,
|
|
81
|
+
"Modal.MountBucket",
|
|
82
|
+
(bucket: string | BucketResource, options: MountBucketOptions) => Effect.Effect<BucketMountRef>
|
|
83
|
+
> {}
|
|
84
|
+
|
|
85
|
+
export const MountBucket = Binding.Service<MountBucket>("Modal.MountBucket");
|
|
86
|
+
|
|
87
|
+
const R2_BUCKET = "Cloudflare.R2.Bucket";
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* {@link MountBucket}: binds the entry into a Modal runtime's `mounts`, or
|
|
91
|
+
* resolves it for `sandboxes.create` in any other runtime.
|
|
92
|
+
*
|
|
93
|
+
* @layer
|
|
94
|
+
* @product Volume
|
|
95
|
+
* @provides Modal.MountBucket
|
|
96
|
+
*/
|
|
97
|
+
export const MountBucketLive = Layer.effect(
|
|
98
|
+
MountBucket,
|
|
99
|
+
Effect.succeed(
|
|
100
|
+
Effect.fn("Modal.MountBucket")(function* (
|
|
101
|
+
bucket: string | BucketResource,
|
|
102
|
+
options: MountBucketOptions,
|
|
103
|
+
) {
|
|
104
|
+
const { secret, ...rest } = options;
|
|
105
|
+
if (!globalThis.__ALCHEMY_RUNTIME__) {
|
|
106
|
+
const host = yield* Binding.Host;
|
|
107
|
+
if (host !== undefined && MODAL_RUNTIMES.has(host.Type)) {
|
|
108
|
+
yield* (host as unknown as MountHost).bind`Modal.MountBucket(${bucket})`({
|
|
109
|
+
mounts: [{ ...rest, bucket, secret }],
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const secretRef = secret === undefined ? undefined : { secretId: yield* secret.secretId };
|
|
114
|
+
if (typeof bucket === "string") {
|
|
115
|
+
return { ...rest, bucket, secret: secretRef } satisfies BucketMountRef;
|
|
116
|
+
}
|
|
117
|
+
const bucketName = yield* bucket.bucketName;
|
|
118
|
+
if (bucket.Type === R2_BUCKET) {
|
|
119
|
+
const r2 = bucket as BucketResource & {
|
|
120
|
+
readonly accountId: Output.Output<string, never>;
|
|
121
|
+
readonly jurisdiction: Output.Output<string | undefined, never>;
|
|
122
|
+
};
|
|
123
|
+
const accountId = yield* r2.accountId;
|
|
124
|
+
const jurisdiction = yield* r2.jurisdiction;
|
|
125
|
+
const endpointUrl = Effect.map(Effect.all([accountId, jurisdiction]), ([account, j]) =>
|
|
126
|
+
r2Endpoint(account, j),
|
|
127
|
+
);
|
|
128
|
+
return {
|
|
129
|
+
...rest,
|
|
130
|
+
bucket: { bucketName, endpointUrl, type: "r2" },
|
|
131
|
+
secret: secretRef,
|
|
132
|
+
} satisfies BucketMountRef;
|
|
133
|
+
}
|
|
134
|
+
return { ...rest, bucket: { bucketName }, secret: secretRef } satisfies BucketMountRef;
|
|
135
|
+
}),
|
|
136
|
+
),
|
|
137
|
+
);
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import * as Binding from "alchemy/Binding";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Layer from "effect/Layer";
|
|
4
|
+
import * as ModalBindings from "./ModalBindings.ts";
|
|
5
|
+
import type { MountedVolume, VolumeMount, VolumeMountOptions } from "./Mounts.ts";
|
|
6
|
+
import type { Volume } from "./Volume.ts";
|
|
7
|
+
|
|
8
|
+
/** What `Modal.MountVolume` returns: a mount entry, ready for `mounts`. */
|
|
9
|
+
export type VolumeMountRef = VolumeMount<MountedVolume>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Mount a `Modal.Volume` at `path`.
|
|
13
|
+
*
|
|
14
|
+
* - In a `Modal.Function`, `Modal.Server` or `Modal.Sandbox` program, the
|
|
15
|
+
* volume is mounted into every container the program runs in: read it at
|
|
16
|
+
* `path` with the filesystem.
|
|
17
|
+
* - In any other runtime (a Worker, a Lambda), the binding grants the
|
|
18
|
+
* runtime's Modal identity access to the volume's environment and returns
|
|
19
|
+
* the entry to pass to `sandboxes.create({ mounts })`.
|
|
20
|
+
*
|
|
21
|
+
* The returned reference holds the same fields as a plain entry
|
|
22
|
+
* (`{ volume, path, readOnly?, subPath? }`).
|
|
23
|
+
*
|
|
24
|
+
* ### Mount into a program
|
|
25
|
+
* **Example:** A Function reading model weights from a volume
|
|
26
|
+
* ```typescript
|
|
27
|
+
* import * as Modal from "@alchemy.run/modal";
|
|
28
|
+
* import * as Effect from "effect/Effect";
|
|
29
|
+
* import * as FileSystem from "effect/FileSystem";
|
|
30
|
+
* import * as HttpServerResponse from "effect/http/HttpServerResponse";
|
|
31
|
+
* import { Backend, Weights } from "./Backend.ts";
|
|
32
|
+
*
|
|
33
|
+
* export default class Embed extends Modal.Function<Embed>()(
|
|
34
|
+
* "Embed",
|
|
35
|
+
* { main: import.meta.url, app: Backend, gpu: "L4" },
|
|
36
|
+
* Effect.gen(function* () {
|
|
37
|
+
* const weights = yield* Modal.MountVolume(Weights, { path: "/weights", readOnly: true });
|
|
38
|
+
* const fs = yield* FileSystem.FileSystem;
|
|
39
|
+
* return {
|
|
40
|
+
* fetch: Effect.gen(function* () {
|
|
41
|
+
* return yield* HttpServerResponse.json(yield* fs.readDirectory(weights.path));
|
|
42
|
+
* }).pipe(Effect.orDie),
|
|
43
|
+
* };
|
|
44
|
+
* }).pipe(Effect.provide(Modal.MountVolumeLive)),
|
|
45
|
+
* ) {}
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* ### Mount into a sandbox you create
|
|
49
|
+
* **Example:** From a Cloudflare Worker
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const data = yield* Modal.MountVolume(Data, { path: "/data" });
|
|
52
|
+
* const sandboxes = yield* Modal.CreateSandbox(Coder);
|
|
53
|
+
* // per request
|
|
54
|
+
* const sandbox = yield* sandboxes.create({ mounts: [data] });
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @binding
|
|
58
|
+
* @product Volume
|
|
59
|
+
*/
|
|
60
|
+
export interface MountVolume extends Binding.Service<
|
|
61
|
+
MountVolume,
|
|
62
|
+
"Modal.MountVolume",
|
|
63
|
+
(volume: Volume, options: VolumeMountOptions) => Effect.Effect<VolumeMountRef>
|
|
64
|
+
> {}
|
|
65
|
+
|
|
66
|
+
export const MountVolume = Binding.Service<MountVolume>("Modal.MountVolume");
|
|
67
|
+
|
|
68
|
+
/** Runtimes that mount volumes into their own containers. */
|
|
69
|
+
export const MODAL_RUNTIMES = new Set(["Modal.Function", "Modal.Server", "Modal.Sandbox"]);
|
|
70
|
+
|
|
71
|
+
/** A Modal runtime's `bind`, typed for the `mounts` slice of its binding contract. */
|
|
72
|
+
export type MountHost = {
|
|
73
|
+
bind: (
|
|
74
|
+
label: TemplateStringsArray,
|
|
75
|
+
...args: unknown[]
|
|
76
|
+
) => (data: { readonly mounts: ReadonlyArray<unknown> }) => Effect.Effect<void>;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* {@link MountVolume}: binds the entry into a Modal runtime's `mounts`, or
|
|
81
|
+
* grants another runtime's identity access to the volume's environment.
|
|
82
|
+
*
|
|
83
|
+
* @layer
|
|
84
|
+
* @product Volume
|
|
85
|
+
* @provides Modal.MountVolume
|
|
86
|
+
*/
|
|
87
|
+
export const MountVolumeLive = Layer.effect(
|
|
88
|
+
MountVolume,
|
|
89
|
+
Effect.gen(function* () {
|
|
90
|
+
const bind = yield* ModalBindings.Bind;
|
|
91
|
+
return Effect.fn("Modal.MountVolume")(function* (volume: Volume, options: VolumeMountOptions) {
|
|
92
|
+
if (!globalThis.__ALCHEMY_RUNTIME__) {
|
|
93
|
+
const host = yield* Binding.Host;
|
|
94
|
+
if (host !== undefined && MODAL_RUNTIMES.has(host.Type)) {
|
|
95
|
+
yield* (host as unknown as MountHost).bind`Modal.MountVolume(${volume})`({
|
|
96
|
+
mounts: [{ volume, ...options }],
|
|
97
|
+
});
|
|
98
|
+
} else {
|
|
99
|
+
yield* bind`Modal.MountVolume(${volume})`({
|
|
100
|
+
roles: [
|
|
101
|
+
{
|
|
102
|
+
environment: volume.environment,
|
|
103
|
+
role: options.readOnly ? "viewer" : "contributor",
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const volumeId = yield* volume.volumeId;
|
|
110
|
+
return { ...options, volume: { volumeId } } satisfies VolumeMountRef;
|
|
111
|
+
});
|
|
112
|
+
}),
|
|
113
|
+
);
|