@alchemy.run/modal 0.0.0 → 2.0.0-beta.87
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
package/src/Mounts.ts
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import type * as sandbox from "@distilled.cloud/modal/sandbox";
|
|
2
|
+
import { checkMountSupport, collectMountCapabilities, type MountCapability } from "alchemy/Mount";
|
|
3
|
+
import * as Output from "alchemy/Output";
|
|
4
|
+
import * as Data from "effect/Data";
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
6
|
+
import type { Ref } from "./Container.ts";
|
|
7
|
+
|
|
8
|
+
/** A value known at deploy, or an Effect that reads it at runtime. */
|
|
9
|
+
type Lazy<T> = T | Effect.Effect<T>;
|
|
10
|
+
|
|
11
|
+
/** A volume entry's options besides the volume: Modal's own volume mount fields. */
|
|
12
|
+
export interface VolumeMountOptions {
|
|
13
|
+
/** Absolute path the volume is mounted at. */
|
|
14
|
+
readonly path: string;
|
|
15
|
+
/** Mount read-only. */
|
|
16
|
+
readonly readOnly?: boolean;
|
|
17
|
+
/** Mount this directory of the volume instead of its root. */
|
|
18
|
+
readonly subPath?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** A bucket entry's options besides the bucket: Modal's own cloud bucket mount fields. */
|
|
22
|
+
export interface BucketMountOptions {
|
|
23
|
+
/** Absolute path the bucket is mounted at. */
|
|
24
|
+
readonly path: string;
|
|
25
|
+
/**
|
|
26
|
+
* The bucket's storage API.
|
|
27
|
+
* @default "r2" for a Cloudflare R2 bucket, "s3" otherwise
|
|
28
|
+
*/
|
|
29
|
+
readonly type?: "s3" | "r2" | "gcp";
|
|
30
|
+
/**
|
|
31
|
+
* S3-compatible endpoint.
|
|
32
|
+
* @default the account endpoint, for a Cloudflare R2 bucket
|
|
33
|
+
*/
|
|
34
|
+
readonly endpointUrl?: string;
|
|
35
|
+
/** Mount only keys under this prefix. */
|
|
36
|
+
readonly keyPrefix?: string;
|
|
37
|
+
/** Mount read-only. */
|
|
38
|
+
readonly readOnly?: boolean;
|
|
39
|
+
/** Assume this AWS role with Modal's OIDC identity instead of a secret. */
|
|
40
|
+
readonly oidcAuthRoleArn?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** The fields of a bucket resource a mount reads: AWS S3, Cloudflare R2, GCS. */
|
|
44
|
+
export interface BucketLike {
|
|
45
|
+
readonly bucketName: string;
|
|
46
|
+
/** Cloudflare R2: the account the bucket's endpoint is under. */
|
|
47
|
+
readonly accountId?: string;
|
|
48
|
+
/** Cloudflare R2: `"eu"` or `"fedramp"` buckets have their own endpoint. */
|
|
49
|
+
readonly jurisdiction?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* A `Modal.Volume` mounted at `path`. In Stack props the volume is the
|
|
54
|
+
* declared `Modal.Volume`; at runtime it's a handle (`CreateVolume`) or
|
|
55
|
+
* the reference `Modal.MountVolume` returns.
|
|
56
|
+
*/
|
|
57
|
+
export interface VolumeMount<V = Ref<{ readonly volumeId: string }>> extends VolumeMountOptions {
|
|
58
|
+
readonly volume: V;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* A cloud bucket mounted at `path` with Modal's cloud bucket mounts: a
|
|
63
|
+
* bucket name, or a bucket resource of another provider (an AWS S3 Bucket,
|
|
64
|
+
* a Cloudflare R2 Bucket). Without `oidcAuthRoleArn`, `secret` holds the
|
|
65
|
+
* bucket's keys (`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`, or GCS HMAC
|
|
66
|
+
* keys).
|
|
67
|
+
*/
|
|
68
|
+
export interface BucketMount<
|
|
69
|
+
B = string | Ref<BucketLike>,
|
|
70
|
+
S = Ref<{ readonly secretId: string }>,
|
|
71
|
+
> extends BucketMountOptions {
|
|
72
|
+
readonly bucket: B;
|
|
73
|
+
readonly secret?: S;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** A mount in Stack props (`Modal.Function`, `Server`, `Sandbox`, `PersistentSandbox`). */
|
|
77
|
+
export type Mount = VolumeMount | BucketMount;
|
|
78
|
+
|
|
79
|
+
/** The volume of a runtime mount entry: a volume handle, or a `MountVolume` reference. */
|
|
80
|
+
export interface MountedVolume {
|
|
81
|
+
readonly volumeId: Lazy<string>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** The bucket of a runtime mount entry, as `MountBucket` resolves it. */
|
|
85
|
+
export interface MountedBucket {
|
|
86
|
+
readonly bucketName: Lazy<string>;
|
|
87
|
+
readonly endpointUrl?: Lazy<string | undefined>;
|
|
88
|
+
readonly type?: "s3" | "r2" | "gcp";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** A mount for `sandboxes.create`: a plain entry over handles, or a `Mount<Noun>` reference. */
|
|
92
|
+
export type SandboxMount =
|
|
93
|
+
| VolumeMount<MountedVolume>
|
|
94
|
+
| BucketMount<string | MountedBucket, { readonly secretId: Lazy<string> }>;
|
|
95
|
+
|
|
96
|
+
/** A mount entry referenced a resource that isn't bound into this runtime. */
|
|
97
|
+
export class MountNotBound extends Data.TaggedError("Modal.MountNotBound")<{
|
|
98
|
+
readonly path: string;
|
|
99
|
+
readonly message: string;
|
|
100
|
+
}> {}
|
|
101
|
+
|
|
102
|
+
/** Modal's mount fields for a set of entries. */
|
|
103
|
+
export interface ModalMounts {
|
|
104
|
+
readonly volumeMounts: sandbox.VolumeMount[];
|
|
105
|
+
readonly cloudBucketMounts: sandbox.CloudBucketMount[];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const BUCKET_TYPE = { s3: "S3", r2: "R2", gcp: "GCP" } as const;
|
|
109
|
+
|
|
110
|
+
/** Cloudflare R2's S3 endpoint for an account (and jurisdiction). */
|
|
111
|
+
export const r2Endpoint = (accountId: string, jurisdiction?: string): string =>
|
|
112
|
+
`https://${accountId}${
|
|
113
|
+
jurisdiction && jurisdiction !== "default" ? `.${jurisdiction}` : ""
|
|
114
|
+
}.r2.cloudflarestorage.com`;
|
|
115
|
+
|
|
116
|
+
const value = <T>(input: Lazy<T> | undefined, path: string) =>
|
|
117
|
+
Output.isOutput(input)
|
|
118
|
+
? Effect.fail(
|
|
119
|
+
new MountNotBound({
|
|
120
|
+
path,
|
|
121
|
+
message: `The mount at ${path} references a declared resource; bind it with Modal.MountVolume or Modal.MountBucket`,
|
|
122
|
+
}),
|
|
123
|
+
)
|
|
124
|
+
: Effect.isEffect(input)
|
|
125
|
+
? (input as Effect.Effect<T>)
|
|
126
|
+
: Effect.succeed(input as T);
|
|
127
|
+
|
|
128
|
+
const field = (record: unknown, key: string): unknown =>
|
|
129
|
+
typeof record === "object" && record !== null
|
|
130
|
+
? (record as Record<string, unknown>)[key]
|
|
131
|
+
: undefined;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Modal's `volumeMounts` and `cloudBucketMounts` for mount entries whose
|
|
135
|
+
* resources are resolved: attributes at reconcile, handles or `Mount<Noun>`
|
|
136
|
+
* references at runtime.
|
|
137
|
+
*/
|
|
138
|
+
export const modalMountsOf = (
|
|
139
|
+
mounts: ReadonlyArray<Mount | SandboxMount> | undefined,
|
|
140
|
+
): Effect.Effect<ModalMounts, MountNotBound> =>
|
|
141
|
+
Effect.gen(function* () {
|
|
142
|
+
const volumeMounts: sandbox.VolumeMount[] = [];
|
|
143
|
+
const cloudBucketMounts: sandbox.CloudBucketMount[] = [];
|
|
144
|
+
for (const mount of mounts ?? []) {
|
|
145
|
+
if ("volume" in mount) {
|
|
146
|
+
const volumeId = yield* value(field(mount.volume, "volumeId") as Lazy<string>, mount.path);
|
|
147
|
+
volumeMounts.push({
|
|
148
|
+
mountPath: mount.path,
|
|
149
|
+
volumeId,
|
|
150
|
+
readOnly: mount.readOnly,
|
|
151
|
+
subPath: mount.subPath,
|
|
152
|
+
allowBackgroundCommits: true,
|
|
153
|
+
});
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const bucket = mount.bucket;
|
|
157
|
+
const bucketName =
|
|
158
|
+
typeof bucket === "string"
|
|
159
|
+
? bucket
|
|
160
|
+
: yield* value(field(bucket, "bucketName") as Lazy<string>, mount.path);
|
|
161
|
+
const accountId = field(bucket, "accountId");
|
|
162
|
+
const isR2 = typeof accountId === "string";
|
|
163
|
+
const endpointUrl =
|
|
164
|
+
mount.endpointUrl ??
|
|
165
|
+
(isR2
|
|
166
|
+
? r2Endpoint(accountId, field(bucket, "jurisdiction") as string | undefined)
|
|
167
|
+
: yield* value(field(bucket, "endpointUrl") as Lazy<string | undefined>, mount.path));
|
|
168
|
+
const type =
|
|
169
|
+
mount.type ?? (field(bucket, "type") as BucketMount["type"]) ?? (isR2 ? "r2" : undefined);
|
|
170
|
+
const secretId = mount.secret
|
|
171
|
+
? yield* value(field(mount.secret, "secretId") as Lazy<string>, mount.path)
|
|
172
|
+
: undefined;
|
|
173
|
+
cloudBucketMounts.push({
|
|
174
|
+
mountPath: mount.path,
|
|
175
|
+
bucketName,
|
|
176
|
+
bucketType: type ? BUCKET_TYPE[type] : undefined,
|
|
177
|
+
bucketEndpointUrl: endpointUrl,
|
|
178
|
+
credentialsSecretId: secretId,
|
|
179
|
+
keyPrefix: mount.keyPrefix,
|
|
180
|
+
readOnly: mount.readOnly,
|
|
181
|
+
oidcAuthRoleArn: mount.oidcAuthRoleArn,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
return { volumeMounts, cloudBucketMounts };
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* What a Modal runtime's `mounts` binding contract holds: volume and bucket
|
|
189
|
+
* entries (`Modal.MountVolume`, `Modal.MountBucket`), and the install lines
|
|
190
|
+
* of other providers' mount clients (`alchemy/Mount`).
|
|
191
|
+
*/
|
|
192
|
+
export type MountContract = ReadonlyArray<Mount | MountCapability>;
|
|
193
|
+
|
|
194
|
+
/** A host's binding data, for its `mounts` slice. */
|
|
195
|
+
export type MountBindings = ReadonlyArray<{ readonly data: { readonly mounts?: MountContract } }>;
|
|
196
|
+
|
|
197
|
+
const isCapability = (entry: Mount | MountCapability): entry is MountCapability =>
|
|
198
|
+
"install" in entry && "id" in entry;
|
|
199
|
+
|
|
200
|
+
/** The volume and bucket entries a host's bindings contributed, in binding order. */
|
|
201
|
+
export const boundMounts = (bindings: MountBindings): ReadonlyArray<Mount> =>
|
|
202
|
+
bindings.flatMap((binding) =>
|
|
203
|
+
(binding.data.mounts ?? []).filter((entry): entry is Mount => !isCapability(entry)),
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
/** The mount clients other providers' bindings asked the host's image to install. */
|
|
207
|
+
export const boundCapabilities = (bindings: MountBindings): ReadonlyArray<MountCapability> =>
|
|
208
|
+
collectMountCapabilities(
|
|
209
|
+
bindings.map((binding) => ({
|
|
210
|
+
data: { mounts: (binding.data.mounts ?? []).filter(isCapability) },
|
|
211
|
+
})),
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* What a Modal container provides to mount clients. Modal runs containers
|
|
216
|
+
* under gVisor without `CAP_SYS_ADMIN`: `/dev/fuse` exists, but `mount`
|
|
217
|
+
* fails with permission denied, for FUSE and NFS alike.
|
|
218
|
+
*/
|
|
219
|
+
export const MODAL_MOUNT_SUPPORT = { fuse: false, nfs: false } as const;
|
|
220
|
+
|
|
221
|
+
/** Fail when a mount client needs what a Modal container can't provide. */
|
|
222
|
+
export const checkModalMounts = (host: string, capabilities: ReadonlyArray<MountCapability>) => {
|
|
223
|
+
const unsupported = checkMountSupport(
|
|
224
|
+
host,
|
|
225
|
+
capabilities,
|
|
226
|
+
MODAL_MOUNT_SUPPORT,
|
|
227
|
+
"Mount Modal volumes and cloud buckets with Modal.MountVolume and Modal.MountBucket instead.",
|
|
228
|
+
);
|
|
229
|
+
return unsupported === undefined ? Effect.void : Effect.fail(unsupported);
|
|
230
|
+
};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import * as persistent from "@distilled.cloud/modal/persistent";
|
|
2
|
+
import { deepEqual, isResolved } from "alchemy/Diff";
|
|
3
|
+
import * as Provider from "alchemy/Provider";
|
|
4
|
+
import { Resource } from "alchemy/Resource";
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
6
|
+
import { envNameOf } from "./internal.ts";
|
|
7
|
+
import { declarable } from "./internal/Declared.ts";
|
|
8
|
+
import type { Mount } from "./Mounts.ts";
|
|
9
|
+
import type { Providers } from "./Providers.ts";
|
|
10
|
+
import {
|
|
11
|
+
createPersistentSandbox,
|
|
12
|
+
persistentSandboxHandle,
|
|
13
|
+
SandboxOps,
|
|
14
|
+
type PersistentSandboxCreateOptions,
|
|
15
|
+
} from "./SandboxClient.ts";
|
|
16
|
+
|
|
17
|
+
export interface PersistentSandboxProps extends Omit<PersistentSandboxCreateOptions, "mounts"> {
|
|
18
|
+
/**
|
|
19
|
+
* Volumes and cloud buckets mounted into every session:
|
|
20
|
+
* `[{ volume: Home, path: "/home/user" }]`. Changing them replaces the box.
|
|
21
|
+
*/
|
|
22
|
+
mounts?: Mount[];
|
|
23
|
+
/** The App the box runs in (`Modal.App`). Changing it replaces the box. */
|
|
24
|
+
app: { readonly appId: string; readonly name?: string; readonly environment?: unknown };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface PersistentSandboxAttributes {
|
|
28
|
+
/** Persistent sandbox ID; pass it (or this resource) to `sandboxes.persistent(...)`. */
|
|
29
|
+
persistentSandboxId: string;
|
|
30
|
+
/** The App the box runs in. */
|
|
31
|
+
appId: string;
|
|
32
|
+
/** Name of that App. */
|
|
33
|
+
appName: string | undefined;
|
|
34
|
+
/** Environment of that App. */
|
|
35
|
+
environment: string | undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A Modal persistent sandbox: one box whose filesystem outlives its
|
|
40
|
+
* sessions. Each session is a regular sandbox that runs up to an hour and
|
|
41
|
+
* pauses after five idle minutes; the next `session()` resumes it from the
|
|
42
|
+
* last session's filesystem. Use it for a long-lived workspace, such as a
|
|
43
|
+
* shared dev box or an agent's home, that the Stack owns.
|
|
44
|
+
*
|
|
45
|
+
* Modal's persistent sandboxes are experimental: they don't take a name,
|
|
46
|
+
* GPUs, `env`, tags or memory snapshots yet. Changing any prop replaces the
|
|
47
|
+
* box (and its files).
|
|
48
|
+
*
|
|
49
|
+
* ### Creating a box
|
|
50
|
+
* **Example:** A dev box on a warm base image
|
|
51
|
+
* ```typescript
|
|
52
|
+
* import * as Modal from "@alchemy.run/modal";
|
|
53
|
+
* import { Coder, Warm } from "./Coder.ts";
|
|
54
|
+
*
|
|
55
|
+
* export const DevBox = Modal.PersistentSandbox("DevBox", { app: Coder, image: Warm, workdir: "/work" });
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* ### Using it at runtime
|
|
59
|
+
* **Example:** Resume it from a Worker
|
|
60
|
+
* ```typescript
|
|
61
|
+
* // construction phase
|
|
62
|
+
* const sandboxes = yield* Modal.CreateSandbox(Coder);
|
|
63
|
+
* const devBoxId = yield* (yield* DevBox).persistentSandboxId;
|
|
64
|
+
* // in fetch:
|
|
65
|
+
* const session = yield* (yield* sandboxes.persistent(yield* devBoxId)).session();
|
|
66
|
+
* const result = yield* session.exec(["git", "status"]);
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* @resource
|
|
70
|
+
* @product Sandbox
|
|
71
|
+
*/
|
|
72
|
+
export const PersistentSandbox = declarable<PersistentSandbox>()(
|
|
73
|
+
Resource<PersistentSandbox>("Modal.PersistentSandbox"),
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
export type PersistentSandbox = Resource<
|
|
77
|
+
"Modal.PersistentSandbox",
|
|
78
|
+
PersistentSandboxProps,
|
|
79
|
+
PersistentSandboxAttributes,
|
|
80
|
+
never,
|
|
81
|
+
Providers
|
|
82
|
+
>;
|
|
83
|
+
|
|
84
|
+
const appOf = (value: PersistentSandboxProps["app"]) => ({
|
|
85
|
+
appId: value.appId,
|
|
86
|
+
appName: value.name,
|
|
87
|
+
environment: envNameOf(value.environment as never),
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
export const PersistentSandboxProvider = () =>
|
|
91
|
+
Provider.effect(
|
|
92
|
+
PersistentSandbox,
|
|
93
|
+
Effect.gen(function* () {
|
|
94
|
+
return {
|
|
95
|
+
stables: ["persistentSandboxId", "appId"],
|
|
96
|
+
diff: Effect.fn(function* ({ news, olds }) {
|
|
97
|
+
if (!isResolved(news) || olds === undefined) return undefined;
|
|
98
|
+
// Modal can't change a persistent sandbox's definition.
|
|
99
|
+
return deepEqual(news, olds) ? undefined : ({ action: "replace" } as const);
|
|
100
|
+
}),
|
|
101
|
+
read: Effect.fn(function* ({ output }) {
|
|
102
|
+
if (output === undefined) return undefined;
|
|
103
|
+
const found = yield* persistent
|
|
104
|
+
.getPersistentSandbox({ persistentSandboxId: output.persistentSandboxId })
|
|
105
|
+
.pipe(Effect.catchTag("PersistentSandboxNotFound", () => Effect.undefined));
|
|
106
|
+
return found?.persistentSandboxId ? output : undefined;
|
|
107
|
+
}),
|
|
108
|
+
reconcile: Effect.fn(function* ({ news, output, session }) {
|
|
109
|
+
const app = appOf(news.app);
|
|
110
|
+
// Observe: the box still exists.
|
|
111
|
+
if (output !== undefined) {
|
|
112
|
+
const found = yield* persistent
|
|
113
|
+
.getPersistentSandbox({ persistentSandboxId: output.persistentSandboxId })
|
|
114
|
+
.pipe(Effect.catchTag("PersistentSandboxNotFound", () => Effect.undefined));
|
|
115
|
+
if (found?.persistentSandboxId) return output;
|
|
116
|
+
}
|
|
117
|
+
// Ensure.
|
|
118
|
+
yield* session.note("Creating persistent sandbox...");
|
|
119
|
+
const { app: _app, ...options } = news;
|
|
120
|
+
// Resolved by the engine: every mount's resource is attributes by now.
|
|
121
|
+
const handle = yield* createPersistentSandbox(
|
|
122
|
+
yield* SandboxOps,
|
|
123
|
+
app,
|
|
124
|
+
options as PersistentSandboxCreateOptions,
|
|
125
|
+
);
|
|
126
|
+
return {
|
|
127
|
+
persistentSandboxId: handle.persistentSandboxId,
|
|
128
|
+
appId: app.appId,
|
|
129
|
+
appName: app.appName,
|
|
130
|
+
environment: app.environment,
|
|
131
|
+
};
|
|
132
|
+
}),
|
|
133
|
+
delete: Effect.fn(function* ({ output }) {
|
|
134
|
+
yield* persistentSandboxHandle(
|
|
135
|
+
yield* SandboxOps,
|
|
136
|
+
output.persistentSandboxId,
|
|
137
|
+
output,
|
|
138
|
+
).terminate();
|
|
139
|
+
}),
|
|
140
|
+
};
|
|
141
|
+
}),
|
|
142
|
+
);
|
package/src/Providers.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { CredentialsStoreLive } from "alchemy/Auth/Credentials";
|
|
2
|
+
import { ProfileStoreLive } from "alchemy/Auth/Profile";
|
|
3
|
+
import * as Provider from "alchemy/Provider";
|
|
4
|
+
import { Random, RandomProvider } from "alchemy/Random";
|
|
5
|
+
import * as FetchHttpClient from "effect/http/FetchHttpClient";
|
|
6
|
+
import * as Layer from "effect/Layer";
|
|
7
|
+
import { App, AppProvider } from "./App.ts";
|
|
8
|
+
import { ModalAuth } from "./AuthProvider.ts";
|
|
9
|
+
import * as Credentials from "./Credentials.ts";
|
|
10
|
+
import { Dict, DictProvider } from "./Dict.ts";
|
|
11
|
+
import { Domain, DomainProvider } from "./Domain.ts";
|
|
12
|
+
import { Endpoint, EndpointProvider } from "./Endpoint.ts";
|
|
13
|
+
import { Environment, EnvironmentProvider } from "./Environment.ts";
|
|
14
|
+
import { Function, FunctionProvider } from "./Function.ts";
|
|
15
|
+
import { FunctionAutoscaler, FunctionAutoscalerProvider } from "./FunctionAutoscaler.ts";
|
|
16
|
+
import { Image, ImageProvider } from "./Image.ts";
|
|
17
|
+
import { PersistentSandbox, PersistentSandboxProvider } from "./PersistentSandbox.ts";
|
|
18
|
+
import { Proxy, ProxyProvider } from "./Proxy.ts";
|
|
19
|
+
import { Queue, QueueProvider } from "./Queue.ts";
|
|
20
|
+
import { Sandbox, SandboxProvider } from "./Sandbox.ts";
|
|
21
|
+
import { Secret, SecretProvider } from "./Secret.ts";
|
|
22
|
+
import { Server, ServerProvider } from "./Server.ts";
|
|
23
|
+
import { ServiceUser, ServiceUserProvider } from "./ServiceUser.ts";
|
|
24
|
+
import { Volume, VolumeProvider } from "./Volume.ts";
|
|
25
|
+
import { WebhookToken, WebhookTokenProvider } from "./WebhookToken.ts";
|
|
26
|
+
import { WorkspaceSettings, WorkspaceSettingsProvider } from "./WorkspaceSettings.ts";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Service tag bundling every Modal provider + auth + credentials. Use
|
|
30
|
+
* `Modal.providers()` to materialize the full layer.
|
|
31
|
+
*/
|
|
32
|
+
export class Providers extends Provider.ProviderCollection<Providers>()("Modal") {}
|
|
33
|
+
|
|
34
|
+
export type ProviderRequirements = Layer.Services<ReturnType<typeof providers>>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Every Modal resource provider, the Modal AuthProvider registration (so
|
|
38
|
+
* `alchemy profile edit` can configure it), and credential resolution.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* Alchemy.Stack("App", { providers: Modal.providers() }, ...)
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export const providers = () =>
|
|
46
|
+
Layer.effect(
|
|
47
|
+
Providers,
|
|
48
|
+
Provider.collection([
|
|
49
|
+
App,
|
|
50
|
+
Dict,
|
|
51
|
+
Domain,
|
|
52
|
+
Endpoint,
|
|
53
|
+
Environment,
|
|
54
|
+
Function,
|
|
55
|
+
FunctionAutoscaler,
|
|
56
|
+
Image,
|
|
57
|
+
PersistentSandbox,
|
|
58
|
+
Proxy,
|
|
59
|
+
Queue,
|
|
60
|
+
// Each RPC binding mints its caller's key (`Modal.InvokeFunction`, `Modal.FetchServer`).
|
|
61
|
+
Random,
|
|
62
|
+
Sandbox,
|
|
63
|
+
Secret,
|
|
64
|
+
Server,
|
|
65
|
+
ServiceUser,
|
|
66
|
+
Volume,
|
|
67
|
+
WebhookToken,
|
|
68
|
+
WorkspaceSettings,
|
|
69
|
+
]),
|
|
70
|
+
).pipe(
|
|
71
|
+
Layer.provide(
|
|
72
|
+
Layer.mergeAll(
|
|
73
|
+
AppProvider(),
|
|
74
|
+
DictProvider(),
|
|
75
|
+
DomainProvider(),
|
|
76
|
+
EndpointProvider(),
|
|
77
|
+
EnvironmentProvider(),
|
|
78
|
+
FunctionProvider(),
|
|
79
|
+
FunctionAutoscalerProvider(),
|
|
80
|
+
ImageProvider(),
|
|
81
|
+
PersistentSandboxProvider(),
|
|
82
|
+
ProxyProvider(),
|
|
83
|
+
QueueProvider(),
|
|
84
|
+
RandomProvider(),
|
|
85
|
+
SandboxProvider(),
|
|
86
|
+
SecretProvider(),
|
|
87
|
+
ServerProvider(),
|
|
88
|
+
ServiceUserProvider(),
|
|
89
|
+
VolumeProvider(),
|
|
90
|
+
WebhookTokenProvider(),
|
|
91
|
+
WorkspaceSettingsProvider(),
|
|
92
|
+
),
|
|
93
|
+
),
|
|
94
|
+
Layer.provideMerge(Credentials.fromAuthProvider()),
|
|
95
|
+
Layer.provideMerge(FetchHttpClient.layer),
|
|
96
|
+
Layer.provideMerge(ModalAuth),
|
|
97
|
+
Layer.provideMerge(ProfileStoreLive),
|
|
98
|
+
Layer.provideMerge(CredentialsStoreLive),
|
|
99
|
+
Layer.orDie,
|
|
100
|
+
);
|
package/src/Proxy.ts
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import * as proxy from "@distilled.cloud/modal/proxy";
|
|
2
|
+
import { Unowned } from "alchemy/AdoptPolicy";
|
|
3
|
+
import { isResolved } from "alchemy/Diff";
|
|
4
|
+
import * as Provider from "alchemy/Provider";
|
|
5
|
+
import { Resource } from "alchemy/Resource";
|
|
6
|
+
import * as Data from "effect/Data";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import {
|
|
9
|
+
type EnvironmentInput,
|
|
10
|
+
envNameOf,
|
|
11
|
+
environmentOf,
|
|
12
|
+
isGeneratedName,
|
|
13
|
+
objectName,
|
|
14
|
+
} from "./internal.ts";
|
|
15
|
+
import { declarable } from "./internal/Declared.ts";
|
|
16
|
+
import type { Providers } from "./Providers.ts";
|
|
17
|
+
|
|
18
|
+
export class ProxyUnexpectedResponse extends Data.TaggedError("Modal.ProxyUnexpectedResponse")<{
|
|
19
|
+
readonly message: string;
|
|
20
|
+
}> {}
|
|
21
|
+
|
|
22
|
+
export interface ProxyProps {
|
|
23
|
+
/**
|
|
24
|
+
* Proxy name, unique per environment. If omitted, a unique name is
|
|
25
|
+
* generated from the stack, stage and logical ID. Changing it replaces the
|
|
26
|
+
* proxy.
|
|
27
|
+
*/
|
|
28
|
+
name?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Environment the proxy lives in. Changing it replaces the proxy.
|
|
31
|
+
* @default the workspace's default environment
|
|
32
|
+
*/
|
|
33
|
+
environment?: EnvironmentInput;
|
|
34
|
+
/**
|
|
35
|
+
* Region the proxy's IPs come from (e.g. `us-east-1`). Changing it
|
|
36
|
+
* replaces the proxy.
|
|
37
|
+
*/
|
|
38
|
+
region?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Number of static egress IPs. Traffic through the proxy leaves from one
|
|
41
|
+
* of them.
|
|
42
|
+
* @default 1
|
|
43
|
+
*/
|
|
44
|
+
ips?: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ProxyAttributes {
|
|
48
|
+
/** Proxy ID (`pr-…`). */
|
|
49
|
+
proxyId: string;
|
|
50
|
+
/** Proxy name. */
|
|
51
|
+
name: string;
|
|
52
|
+
/** Environment name, or `undefined` for the workspace default. */
|
|
53
|
+
environment: string | undefined;
|
|
54
|
+
/** Region of the proxy's IPs. */
|
|
55
|
+
region: string | undefined;
|
|
56
|
+
/** The static egress IPs, for allowlists on the systems a sandbox calls. */
|
|
57
|
+
ips: string[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* A Modal Proxy: static egress IPs for Sandboxes and Functions. Traffic from
|
|
62
|
+
* a sandbox created with `proxy` leaves from these IPs, so a database or API
|
|
63
|
+
* can allowlist them.
|
|
64
|
+
*
|
|
65
|
+
* Proxies are a Modal Team plan feature. Modal proxies have no tags;
|
|
66
|
+
* ownership is inferred from Alchemy state.
|
|
67
|
+
*
|
|
68
|
+
* ### Creating a Proxy
|
|
69
|
+
* **Example:** One static IP
|
|
70
|
+
* ```typescript
|
|
71
|
+
* import * as Modal from "@alchemy.run/modal";
|
|
72
|
+
*
|
|
73
|
+
* export const Egress = Modal.Proxy("Egress", {});
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* **Example:** Two IPs in a region
|
|
77
|
+
* ```typescript
|
|
78
|
+
* import * as Modal from "@alchemy.run/modal";
|
|
79
|
+
*
|
|
80
|
+
* export const Egress = Modal.Proxy("Egress", { region: "us-east-1", ips: 2 });
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* ### Routing a Sandbox through it
|
|
84
|
+
* **Example:** Pass the proxy when creating a sandbox
|
|
85
|
+
* ```typescript
|
|
86
|
+
* const sandbox = yield* sandboxes.create({ proxy: egress });
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* @resource
|
|
90
|
+
* @product Proxy
|
|
91
|
+
*/
|
|
92
|
+
export const Proxy = declarable<Proxy>()(Resource<Proxy>("Modal.Proxy"));
|
|
93
|
+
|
|
94
|
+
export type Proxy = Resource<"Modal.Proxy", ProxyProps, ProxyAttributes, never, Providers>;
|
|
95
|
+
|
|
96
|
+
const toAttrs = (p: proxy.Proxy, env: string | undefined): ProxyAttributes => ({
|
|
97
|
+
proxyId: p.proxyId ?? "",
|
|
98
|
+
name: p.name ?? "",
|
|
99
|
+
environment: env,
|
|
100
|
+
region: p.region || undefined,
|
|
101
|
+
ips: (p.proxyIps ?? []).flatMap((ip) => (ip.proxyIp ? [ip.proxyIp] : [])),
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
export const ProxyProvider = () =>
|
|
105
|
+
Provider.effect(
|
|
106
|
+
Proxy,
|
|
107
|
+
Effect.gen(function* () {
|
|
108
|
+
const observe = Effect.fn(function* (name: string, env: string | undefined) {
|
|
109
|
+
const found = yield* proxy
|
|
110
|
+
.getProxy({ name, environmentName: environmentOf(env) })
|
|
111
|
+
.pipe(Effect.catchTag("ProxyNotFound", () => Effect.undefined));
|
|
112
|
+
return found?.proxy?.proxyId ? found.proxy : undefined;
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
stables: ["proxyId", "name", "environment", "region"],
|
|
117
|
+
diff: Effect.fn(function* ({ id, news, olds, output }) {
|
|
118
|
+
if (!isResolved(news)) return undefined;
|
|
119
|
+
if (envNameOf(news.environment) !== envNameOf(olds?.environment))
|
|
120
|
+
return { action: "replace" } as const;
|
|
121
|
+
if (news.region !== olds?.region) return { action: "replace" } as const;
|
|
122
|
+
const name = yield* objectName(id, news.name);
|
|
123
|
+
if (output !== undefined && name !== output.name) return { action: "replace" } as const;
|
|
124
|
+
return undefined;
|
|
125
|
+
}),
|
|
126
|
+
read: Effect.fn(function* ({ id, olds, output }) {
|
|
127
|
+
const name = output?.name ?? (yield* objectName(id, olds?.name));
|
|
128
|
+
const env = output?.environment ?? envNameOf(olds?.environment);
|
|
129
|
+
const found = yield* observe(name, env);
|
|
130
|
+
if (!found) return undefined;
|
|
131
|
+
const attrs = toAttrs(found, env);
|
|
132
|
+
return output !== undefined || olds?.name === undefined ? attrs : Unowned(attrs);
|
|
133
|
+
}),
|
|
134
|
+
reconcile: Effect.fn(function* ({ id, news, output, session }) {
|
|
135
|
+
const name = output?.name ?? (yield* objectName(id, news.name));
|
|
136
|
+
// Observe
|
|
137
|
+
let current = yield* observe(name, envNameOf(news.environment));
|
|
138
|
+
// Ensure
|
|
139
|
+
if (!current) {
|
|
140
|
+
yield* session.note(`Creating proxy ${name}...`);
|
|
141
|
+
const created = yield* proxy
|
|
142
|
+
.createProxy({
|
|
143
|
+
name,
|
|
144
|
+
environmentName: environmentOf(envNameOf(news.environment)),
|
|
145
|
+
region: news.region,
|
|
146
|
+
})
|
|
147
|
+
.pipe(
|
|
148
|
+
Effect.map((response) => response.proxy),
|
|
149
|
+
Effect.catchTag("ProxyAlreadyExists", () =>
|
|
150
|
+
observe(name, envNameOf(news.environment)),
|
|
151
|
+
),
|
|
152
|
+
);
|
|
153
|
+
if (!created?.proxyId) {
|
|
154
|
+
return yield* new ProxyUnexpectedResponse({
|
|
155
|
+
message: `Modal returned no proxy for ${name}`,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
current = created;
|
|
159
|
+
}
|
|
160
|
+
// Sync the IP count against the observed IPs.
|
|
161
|
+
const desired = news.ips ?? 1;
|
|
162
|
+
const observed = (current.proxyIps ?? []).flatMap((ip) =>
|
|
163
|
+
ip.proxyIp ? [ip.proxyIp] : [],
|
|
164
|
+
);
|
|
165
|
+
for (let i = observed.length; i < desired; i++) {
|
|
166
|
+
yield* session.note(`Adding an IP to proxy ${name}...`);
|
|
167
|
+
yield* proxy.proxyAddIp({ proxyId: current.proxyId });
|
|
168
|
+
}
|
|
169
|
+
for (const ip of observed.slice(desired)) {
|
|
170
|
+
yield* session.note(`Removing IP ${ip} from proxy ${name}...`);
|
|
171
|
+
yield* proxy
|
|
172
|
+
.proxyRemoveIp({ proxyIp: ip })
|
|
173
|
+
.pipe(Effect.catchTag("ProxyNotFound", () => Effect.void));
|
|
174
|
+
}
|
|
175
|
+
const final = (yield* observe(name, envNameOf(news.environment))) ?? current;
|
|
176
|
+
return toAttrs(final, envNameOf(news.environment));
|
|
177
|
+
}),
|
|
178
|
+
delete: Effect.fn(function* ({ output }) {
|
|
179
|
+
yield* proxy
|
|
180
|
+
.deleteProxy({ proxyId: output.proxyId })
|
|
181
|
+
.pipe(Effect.catchTag("ProxyNotFound", () => Effect.void));
|
|
182
|
+
}),
|
|
183
|
+
list: Effect.fn(function* () {
|
|
184
|
+
const { proxies } = yield* proxy.listProxy({});
|
|
185
|
+
return (proxies ?? [])
|
|
186
|
+
.filter((p) => p.proxyId && isGeneratedName(p.name))
|
|
187
|
+
.map((p) => toAttrs(p, p.environmentName || undefined));
|
|
188
|
+
}),
|
|
189
|
+
};
|
|
190
|
+
}),
|
|
191
|
+
);
|