@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
package/src/Function.ts
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import type * as functions from "@distilled.cloud/modal/functions";
|
|
2
|
+
import { Platform, type Main, type MainRpc } from "alchemy/Platform";
|
|
3
|
+
import * as Provider from "alchemy/Provider";
|
|
4
|
+
import type { Resource } from "alchemy/Resource";
|
|
5
|
+
import type { HostRuntimeContext, ServerHost } from "alchemy/Runtime/Process";
|
|
6
|
+
import * as Data from "effect/Data";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import type { ContainerProps } from "./Container.ts";
|
|
9
|
+
import { seconds } from "./internal.ts";
|
|
10
|
+
import { ENTRYPOINT, RPC_SERVE_ENV } from "./internal/Entrypoint.ts";
|
|
11
|
+
import { createModalRuntimeContext, rpcMethodNamesOf } from "./internal/Rpc.ts";
|
|
12
|
+
import {
|
|
13
|
+
resolveContainerProps,
|
|
14
|
+
runtimeLifecycle,
|
|
15
|
+
type RuntimeAttributes,
|
|
16
|
+
} from "./internal/Runtime.ts";
|
|
17
|
+
import type { MountContract } from "./Mounts.ts";
|
|
18
|
+
import type { Providers } from "./Providers.ts";
|
|
19
|
+
import type { DurationInput } from "./SandboxClient.ts";
|
|
20
|
+
|
|
21
|
+
/** Serve the function on the web at a `*.modal.run` URL. */
|
|
22
|
+
export interface WebEndpointOptions {
|
|
23
|
+
/**
|
|
24
|
+
* Label in the URL (`https://<workspace>--<label>.modal.run`).
|
|
25
|
+
* @default "<app>-<function>"
|
|
26
|
+
*/
|
|
27
|
+
label?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Require Modal's proxy auth headers (`Modal-Key` / `Modal-Secret`, from a
|
|
30
|
+
* `Modal.WebhookToken`) on every request.
|
|
31
|
+
* @default false
|
|
32
|
+
*/
|
|
33
|
+
requiresProxyAuth?: boolean;
|
|
34
|
+
/** Custom domains (verified `Modal.Domain`s) that also serve the endpoint. */
|
|
35
|
+
customDomains?: string[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Run the function on a schedule: a cron expression, or a fixed period. */
|
|
39
|
+
export type FunctionSchedule =
|
|
40
|
+
| {
|
|
41
|
+
/** Cron expression (`"0 9 * * 1-5"`). */
|
|
42
|
+
readonly cron: string;
|
|
43
|
+
/** IANA time zone the expression is read in. @default "UTC" */
|
|
44
|
+
readonly timezone?: string;
|
|
45
|
+
}
|
|
46
|
+
| {
|
|
47
|
+
/** Time between runs (`"1 hour"`, or seconds). */
|
|
48
|
+
readonly period: DurationInput;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** Retry failed calls. */
|
|
52
|
+
export interface FunctionRetries {
|
|
53
|
+
/** Retries after the first failure. */
|
|
54
|
+
readonly maxRetries: number;
|
|
55
|
+
/** Delay multiplier per retry; `1` is a fixed delay. @default 2 */
|
|
56
|
+
readonly backoffCoefficient?: number;
|
|
57
|
+
/** Delay before the first retry. @default 1 second */
|
|
58
|
+
readonly initialDelay?: DurationInput;
|
|
59
|
+
/** Longest delay between retries, at most 60 seconds. @default 60 seconds */
|
|
60
|
+
readonly maxDelay?: DurationInput;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface FunctionProps extends ContainerProps {
|
|
64
|
+
/**
|
|
65
|
+
* Serve the program's `fetch` handler on the web instead of taking calls.
|
|
66
|
+
* The URL is the `url` attribute.
|
|
67
|
+
*/
|
|
68
|
+
web?: boolean | WebEndpointOptions;
|
|
69
|
+
/**
|
|
70
|
+
* Run on a schedule. Each tick arrives at the program's `fetch` handler
|
|
71
|
+
* as `POST /__modal/schedule`.
|
|
72
|
+
*/
|
|
73
|
+
schedule?: FunctionSchedule;
|
|
74
|
+
/** Retry failed calls: a count, or a backoff policy. Not for web functions. */
|
|
75
|
+
retries?: number | FunctionRetries;
|
|
76
|
+
/** Most inputs one container handles at once. @default 1 */
|
|
77
|
+
maxConcurrentInputs?: number;
|
|
78
|
+
/** Inputs per container the autoscaler aims for (at most `maxConcurrentInputs`). */
|
|
79
|
+
targetConcurrentInputs?: number;
|
|
80
|
+
/** Shut each container down after it handles one input. */
|
|
81
|
+
singleUseContainers?: boolean;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface FunctionAttributes extends RuntimeAttributes {
|
|
85
|
+
/** The web endpoint's URL, for a function with `web`. */
|
|
86
|
+
url: string | undefined;
|
|
87
|
+
/** The program's RPC methods, which `Modal.InvokeFunction` calls. */
|
|
88
|
+
methods: string[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** A Function's program returns RPC methods and also asks for `web` or a `schedule`. */
|
|
92
|
+
export class FunctionRpcConflict extends Data.TaggedError("Modal.FunctionRpcConflict")<{
|
|
93
|
+
readonly message: string;
|
|
94
|
+
}> {}
|
|
95
|
+
|
|
96
|
+
export type Function = Resource<
|
|
97
|
+
"Modal.Function",
|
|
98
|
+
FunctionProps,
|
|
99
|
+
FunctionAttributes,
|
|
100
|
+
{ env?: Record<string, any>; mounts?: MountContract; rpcCallers?: string[] },
|
|
101
|
+
Providers
|
|
102
|
+
>;
|
|
103
|
+
|
|
104
|
+
export type FunctionServices = ServerHost;
|
|
105
|
+
/**
|
|
106
|
+
* What the program returns: `fetch` for HTTP, and any other functions,
|
|
107
|
+
* its RPC methods.
|
|
108
|
+
*/
|
|
109
|
+
export type FunctionShape =
|
|
110
|
+
| Main<FunctionServices>
|
|
111
|
+
| (Exclude<Main<FunctionServices>, void> & MainRpc<FunctionServices>);
|
|
112
|
+
export type FunctionRuntimeContext = HostRuntimeContext;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* A Modal Function running your program: Modal scales its containers with
|
|
116
|
+
* demand (to zero when idle), and the function takes calls, runs on a
|
|
117
|
+
* schedule, or serves the web.
|
|
118
|
+
*
|
|
119
|
+
* Alchemy bundles `main`, builds it into an image on Modal's builder (no
|
|
120
|
+
* Docker), and deploys the function into its `Modal.App`. Modal starts each
|
|
121
|
+
* container with its Python entrypoint; Alchemy's entrypoint starts your
|
|
122
|
+
* program and hands it work:
|
|
123
|
+
*
|
|
124
|
+
* - the program's RPC methods (every function it returns besides `fetch`)
|
|
125
|
+
* become the function's methods: `Modal.InvokeFunction` calls them with
|
|
126
|
+
* typed arguments and results, and Modal queues, retries and autoscales
|
|
127
|
+
* the calls;
|
|
128
|
+
* - with `web`, Modal routes the function's `*.modal.run` URL to the
|
|
129
|
+
* program's `fetch` handler;
|
|
130
|
+
* - a `schedule` tick arrives at `fetch` as `POST /__modal/schedule`.
|
|
131
|
+
*
|
|
132
|
+
* A function serves one of these. To serve methods next to `fetch`, use a
|
|
133
|
+
* `Modal.Server`. The program's env, including the credentials its
|
|
134
|
+
* bindings need, goes into a Modal Secret, never into the image.
|
|
135
|
+
*
|
|
136
|
+
* ### Effect program
|
|
137
|
+
* **Example:** A function other runtimes call
|
|
138
|
+
* ```typescript
|
|
139
|
+
* // src/Embed.ts
|
|
140
|
+
* import * as Modal from "@alchemy.run/modal";
|
|
141
|
+
* import * as Effect from "effect/Effect";
|
|
142
|
+
* import { Inference } from "./Inference.ts";
|
|
143
|
+
*
|
|
144
|
+
* export default class Embed extends Modal.Function<Embed>()(
|
|
145
|
+
* "Embed",
|
|
146
|
+
* { main: import.meta.url, app: Inference },
|
|
147
|
+
* Effect.gen(function* () {
|
|
148
|
+
* return {
|
|
149
|
+
* embed: Effect.fn(function* (text: string) {
|
|
150
|
+
* return { tokens: text.split(/\s+/).length };
|
|
151
|
+
* }),
|
|
152
|
+
* };
|
|
153
|
+
* }),
|
|
154
|
+
* ) {}
|
|
155
|
+
* ```
|
|
156
|
+
*
|
|
157
|
+
* **Example:** Call it from a Cloudflare Worker
|
|
158
|
+
* ```typescript
|
|
159
|
+
* const embed = yield* Modal.InvokeFunction(Embed);
|
|
160
|
+
* const { tokens } = yield* embed.embed("hello modal");
|
|
161
|
+
* ```
|
|
162
|
+
*
|
|
163
|
+
* ### Async program
|
|
164
|
+
* **Example:** A plain HTTP server, no Effect (it runs on Bun)
|
|
165
|
+
* ```typescript
|
|
166
|
+
* // src/Embed.ts
|
|
167
|
+
* import * as Modal from "@alchemy.run/modal";
|
|
168
|
+
* import { Inference } from "./Inference.ts";
|
|
169
|
+
*
|
|
170
|
+
* export const Embed = Modal.Function("Embed", {
|
|
171
|
+
* main: "./src/embed-server.ts",
|
|
172
|
+
* app: Inference,
|
|
173
|
+
* env: { MODEL: "small" },
|
|
174
|
+
* });
|
|
175
|
+
* export type EmbedEnv = Modal.InferEnv<typeof Embed>;
|
|
176
|
+
* ```
|
|
177
|
+
*
|
|
178
|
+
* ```typescript
|
|
179
|
+
* // src/embed-server.ts
|
|
180
|
+
* import type { EmbedEnv } from "./Embed.ts";
|
|
181
|
+
*
|
|
182
|
+
* const env = process.env as unknown as EmbedEnv;
|
|
183
|
+
*
|
|
184
|
+
* Bun.serve({
|
|
185
|
+
* port: Number(process.env.PORT),
|
|
186
|
+
* async fetch(request) {
|
|
187
|
+
* const { args } = (await request.json()) as { args: [string] };
|
|
188
|
+
* return Response.json({ model: env.MODEL, tokens: args[0].split(/\s+/).length });
|
|
189
|
+
* },
|
|
190
|
+
* });
|
|
191
|
+
* ```
|
|
192
|
+
*
|
|
193
|
+
* ### Web endpoints
|
|
194
|
+
* **Example:** Serve `fetch` at a `*.modal.run` URL
|
|
195
|
+
* ```typescript
|
|
196
|
+
* export default class Api extends Modal.Function<Api>()(
|
|
197
|
+
* "Api",
|
|
198
|
+
* { main: import.meta.url, app: Inference, web: true },
|
|
199
|
+
* Effect.gen(function* () {
|
|
200
|
+
* return { fetch: Effect.succeed(HttpServerResponse.text("hello from Modal")) };
|
|
201
|
+
* }),
|
|
202
|
+
* ) {}
|
|
203
|
+
* ```
|
|
204
|
+
*
|
|
205
|
+
* **Example:** Behind Modal's proxy auth
|
|
206
|
+
* ```typescript
|
|
207
|
+
* export default class Admin extends Modal.Function<Admin>()(
|
|
208
|
+
* "Admin",
|
|
209
|
+
* { main: import.meta.url, app: Inference, web: { requiresProxyAuth: true, label: "admin" } },
|
|
210
|
+
* program,
|
|
211
|
+
* ) {}
|
|
212
|
+
* ```
|
|
213
|
+
*
|
|
214
|
+
* ### Schedules
|
|
215
|
+
* **Example:** Run every morning
|
|
216
|
+
* ```typescript
|
|
217
|
+
* export default class Digest extends Modal.Function<Digest>()(
|
|
218
|
+
* "Digest",
|
|
219
|
+
* { main: import.meta.url, app: Inference, schedule: { cron: "0 9 * * *", timezone: "Europe/London" } },
|
|
220
|
+
* Effect.gen(function* () {
|
|
221
|
+
* return {
|
|
222
|
+
* fetch: Effect.gen(function* () {
|
|
223
|
+
* yield* Effect.log("sending the digest");
|
|
224
|
+
* return yield* HttpServerResponse.json(null);
|
|
225
|
+
* }),
|
|
226
|
+
* };
|
|
227
|
+
* }),
|
|
228
|
+
* ) {}
|
|
229
|
+
* ```
|
|
230
|
+
*
|
|
231
|
+
* ### GPUs, volumes and scaling
|
|
232
|
+
* **Example:** A warm GPU function reading weights from a volume
|
|
233
|
+
* ```typescript
|
|
234
|
+
* export default class Generate extends Modal.Function<Generate>()(
|
|
235
|
+
* "Generate",
|
|
236
|
+
* {
|
|
237
|
+
* main: import.meta.url,
|
|
238
|
+
* app: Inference,
|
|
239
|
+
* gpu: "L4",
|
|
240
|
+
* mounts: [{ volume: Weights, path: "/models" }],
|
|
241
|
+
* minContainers: 1,
|
|
242
|
+
* scaledownWindow: 300,
|
|
243
|
+
* maxConcurrentInputs: 8,
|
|
244
|
+
* timeout: "10 minutes",
|
|
245
|
+
* },
|
|
246
|
+
* program,
|
|
247
|
+
* ) {}
|
|
248
|
+
* ```
|
|
249
|
+
*
|
|
250
|
+
* @resource
|
|
251
|
+
* @product Function
|
|
252
|
+
*/
|
|
253
|
+
export const Function: Platform<Function, FunctionServices, FunctionShape, FunctionRuntimeContext> =
|
|
254
|
+
Platform("Modal.Function", {
|
|
255
|
+
createRuntimeContext: createModalRuntimeContext("Modal.Function"),
|
|
256
|
+
transformProps: resolveContainerProps,
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
const bootstrapEntry =
|
|
260
|
+
(handler: string) =>
|
|
261
|
+
(importPath: string): string =>
|
|
262
|
+
`
|
|
263
|
+
import { bootstrap } from "@alchemy.run/modal/Bootstrap";
|
|
264
|
+
import { ${handler} as entrypoint } from ${JSON.stringify(importPath)};
|
|
265
|
+
|
|
266
|
+
await bootstrap(entrypoint);
|
|
267
|
+
`;
|
|
268
|
+
|
|
269
|
+
const scheduleOf = (schedule: FunctionSchedule | undefined): functions.Schedule | undefined =>
|
|
270
|
+
schedule === undefined
|
|
271
|
+
? undefined
|
|
272
|
+
: "cron" in schedule
|
|
273
|
+
? { cron: { cronString: schedule.cron, timezone: schedule.timezone ?? "UTC" } }
|
|
274
|
+
: { period: { seconds: seconds(schedule.period) } };
|
|
275
|
+
|
|
276
|
+
const retriesOf = (
|
|
277
|
+
retries: number | FunctionRetries | undefined,
|
|
278
|
+
): functions.FunctionRetryPolicy | undefined =>
|
|
279
|
+
retries === undefined
|
|
280
|
+
? undefined
|
|
281
|
+
: typeof retries === "number"
|
|
282
|
+
? { retries, backoffCoefficient: 1, initialDelayMs: 1000, maxDelayMs: 60_000 }
|
|
283
|
+
: {
|
|
284
|
+
retries: retries.maxRetries,
|
|
285
|
+
backoffCoefficient: retries.backoffCoefficient ?? 2,
|
|
286
|
+
initialDelayMs: Math.round((seconds(retries.initialDelay) ?? 1) * 1000),
|
|
287
|
+
maxDelayMs: Math.round((seconds(retries.maxDelay) ?? 60) * 1000),
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
/** How a Function differs from the other runtimes: a call, schedule or web function. */
|
|
291
|
+
const definitionOf = (
|
|
292
|
+
props: FunctionProps,
|
|
293
|
+
context: { readonly port: number; readonly startupTimeout: number },
|
|
294
|
+
): functions.Function => {
|
|
295
|
+
const methods = rpcMethodNamesOf(props.env);
|
|
296
|
+
if (methods.length > 0) {
|
|
297
|
+
// One method per RPC method: callers send its name as the input's
|
|
298
|
+
// `method_name`, and the entrypoint's `Rpc` class forwards it to the
|
|
299
|
+
// program's `/__rpc__/<method>`.
|
|
300
|
+
const formats = ["DATA_FORMAT_PICKLE", "DATA_FORMAT_CBOR"];
|
|
301
|
+
return {
|
|
302
|
+
implementationName: ENTRYPOINT.rpc,
|
|
303
|
+
isClass: true,
|
|
304
|
+
methodDefinitions: Object.fromEntries(
|
|
305
|
+
methods.map((name) => [
|
|
306
|
+
name,
|
|
307
|
+
{
|
|
308
|
+
functionName: name,
|
|
309
|
+
functionType: "FUNCTION_TYPE_FUNCTION",
|
|
310
|
+
supportedInputFormats: formats,
|
|
311
|
+
supportedOutputFormats: formats,
|
|
312
|
+
},
|
|
313
|
+
]),
|
|
314
|
+
),
|
|
315
|
+
supportedInputFormats: formats,
|
|
316
|
+
supportedOutputFormats: formats,
|
|
317
|
+
retryPolicy: retriesOf(props.retries),
|
|
318
|
+
maxConcurrentInputs: props.maxConcurrentInputs ?? 0,
|
|
319
|
+
targetConcurrentInputs: props.targetConcurrentInputs ?? 0,
|
|
320
|
+
singleUseContainers: props.singleUseContainers,
|
|
321
|
+
maxInputs: props.singleUseContainers ? 1 : 0,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
if (props.web) {
|
|
325
|
+
const web = props.web === true ? {} : props.web;
|
|
326
|
+
return {
|
|
327
|
+
implementationName: ENTRYPOINT.web,
|
|
328
|
+
webhookConfig: {
|
|
329
|
+
type: "WEBHOOK_TYPE_WEB_SERVER",
|
|
330
|
+
webServerPort: context.port,
|
|
331
|
+
webServerStartupTimeout: context.startupTimeout,
|
|
332
|
+
requestedSuffix: web.label,
|
|
333
|
+
requiresProxyAuth: web.requiresProxyAuth,
|
|
334
|
+
customDomains: web.customDomains?.map((name) => ({ name })),
|
|
335
|
+
},
|
|
336
|
+
supportedInputFormats: ["DATA_FORMAT_ASGI"],
|
|
337
|
+
supportedOutputFormats: ["DATA_FORMAT_ASGI", "DATA_FORMAT_GENERATOR_DONE"],
|
|
338
|
+
schedule: scheduleOf(props.schedule),
|
|
339
|
+
maxConcurrentInputs: props.maxConcurrentInputs ?? 0,
|
|
340
|
+
targetConcurrentInputs: props.targetConcurrentInputs ?? 0,
|
|
341
|
+
singleUseContainers: props.singleUseContainers,
|
|
342
|
+
maxInputs: props.singleUseContainers ? 1 : 0,
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
return {
|
|
346
|
+
implementationName: props.schedule ? ENTRYPOINT.schedule : ENTRYPOINT.call,
|
|
347
|
+
supportedInputFormats: ["DATA_FORMAT_PICKLE", "DATA_FORMAT_CBOR"],
|
|
348
|
+
supportedOutputFormats: ["DATA_FORMAT_PICKLE", "DATA_FORMAT_CBOR"],
|
|
349
|
+
schedule: scheduleOf(props.schedule),
|
|
350
|
+
retryPolicy: retriesOf(props.retries),
|
|
351
|
+
maxConcurrentInputs: props.maxConcurrentInputs ?? 0,
|
|
352
|
+
targetConcurrentInputs: props.targetConcurrentInputs ?? 0,
|
|
353
|
+
singleUseContainers: props.singleUseContainers,
|
|
354
|
+
maxInputs: props.singleUseContainers ? 1 : 0,
|
|
355
|
+
};
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
export const FunctionProvider = () =>
|
|
359
|
+
Provider.effect(
|
|
360
|
+
Function,
|
|
361
|
+
Effect.gen(function* () {
|
|
362
|
+
const lifecycle = yield* runtimeLifecycle<FunctionProps>({
|
|
363
|
+
type: "Modal.Function",
|
|
364
|
+
definition: definitionOf,
|
|
365
|
+
bootstrap: bootstrapEntry,
|
|
366
|
+
// Modal authenticates every call of a class function, so its
|
|
367
|
+
// program serves RPC (see `createModalRuntimeContext`).
|
|
368
|
+
env: (props): Record<string, string> =>
|
|
369
|
+
rpcMethodNamesOf(props.env).length > 0 ? { [RPC_SERVE_ENV]: "1" } : {},
|
|
370
|
+
});
|
|
371
|
+
return {
|
|
372
|
+
stables: lifecycle.stables,
|
|
373
|
+
diff: lifecycle.diff,
|
|
374
|
+
read: Effect.fn(function* ({ output }) {
|
|
375
|
+
const found = yield* lifecycle.read({ output });
|
|
376
|
+
return found === undefined ? undefined : (output as FunctionAttributes);
|
|
377
|
+
}),
|
|
378
|
+
reconcile: Effect.fn(function* ({ id, news, output, session, bindings }) {
|
|
379
|
+
const methods = rpcMethodNamesOf(news.env);
|
|
380
|
+
if (methods.length > 0 && (news.web || news.schedule)) {
|
|
381
|
+
return yield* new FunctionRpcConflict({
|
|
382
|
+
message: `${id} returns RPC methods (${methods.join(", ")}) and sets ${news.web ? "web" : "schedule"}: a Modal.Function serves calls to its methods, a web endpoint or a schedule. Serve methods next to fetch with a Modal.Server.`,
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
const { attributes, metadata } = yield* lifecycle.reconcile({
|
|
386
|
+
id,
|
|
387
|
+
news,
|
|
388
|
+
output,
|
|
389
|
+
session,
|
|
390
|
+
bindings,
|
|
391
|
+
});
|
|
392
|
+
return { ...attributes, url: news.web ? metadata?.webUrl : undefined, methods };
|
|
393
|
+
}),
|
|
394
|
+
delete: lifecycle.delete,
|
|
395
|
+
};
|
|
396
|
+
}),
|
|
397
|
+
);
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import * as functions from "@distilled.cloud/modal/functions";
|
|
2
|
+
import { isResolved } from "alchemy/Diff";
|
|
3
|
+
import * as Provider from "alchemy/Provider";
|
|
4
|
+
import { Resource } from "alchemy/Resource";
|
|
5
|
+
import * as Data from "effect/Data";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import { type EnvironmentInput, envNameOf, environmentOf, seconds } from "./internal.ts";
|
|
8
|
+
import { declarable } from "./internal/Declared.ts";
|
|
9
|
+
import type { Providers } from "./Providers.ts";
|
|
10
|
+
|
|
11
|
+
export class FunctionAutoscalerUnexpectedResponse extends Data.TaggedError(
|
|
12
|
+
"Modal.FunctionAutoscalerUnexpectedResponse",
|
|
13
|
+
)<{
|
|
14
|
+
readonly message: string;
|
|
15
|
+
}> {}
|
|
16
|
+
|
|
17
|
+
export interface FunctionAutoscalerProps {
|
|
18
|
+
/** Name of the deployed App that defines the function. */
|
|
19
|
+
app: string;
|
|
20
|
+
/**
|
|
21
|
+
* The function's name in the App (`"f"` for `@app.function() def f`, or
|
|
22
|
+
* `"Model.*"` for a class). Changing it, the app or the environment
|
|
23
|
+
* replaces this resource.
|
|
24
|
+
*/
|
|
25
|
+
function: string;
|
|
26
|
+
/**
|
|
27
|
+
* Environment the App is deployed in.
|
|
28
|
+
* @default the workspace's default environment
|
|
29
|
+
*/
|
|
30
|
+
environment?: EnvironmentInput;
|
|
31
|
+
/** Containers kept running even with no inputs (`min_containers`). */
|
|
32
|
+
minContainers?: number;
|
|
33
|
+
/** Most containers the function runs at once (`max_containers`). */
|
|
34
|
+
maxContainers?: number;
|
|
35
|
+
/** Extra idle containers kept ready while the function is busy (`buffer_containers`). */
|
|
36
|
+
bufferContainers?: number;
|
|
37
|
+
/** How long an idle container stays up before scaling down (`scaledown_window`). */
|
|
38
|
+
scaledownWindow?: number | string;
|
|
39
|
+
/** Sustained demand needed before scaling up (`scaleup_window`). */
|
|
40
|
+
scaleupWindow?: number | string;
|
|
41
|
+
/** Inputs each container handles at once before more are added. */
|
|
42
|
+
targetConcurrency?: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** The autoscaler settings Modal stores for a function. */
|
|
46
|
+
export interface AutoscalerSettingsState {
|
|
47
|
+
minContainers?: number;
|
|
48
|
+
maxContainers?: number;
|
|
49
|
+
bufferContainers?: number;
|
|
50
|
+
scaledownWindow?: number;
|
|
51
|
+
scaleupWindow?: number;
|
|
52
|
+
targetConcurrency?: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface FunctionAutoscalerAttributes {
|
|
56
|
+
/** Function ID (`fu-…`). */
|
|
57
|
+
functionId: string;
|
|
58
|
+
/** The settings in effect after the last deploy. */
|
|
59
|
+
settings: AutoscalerSettingsState;
|
|
60
|
+
/** The settings found before the first deploy, restored on destroy. */
|
|
61
|
+
original: AutoscalerSettingsState;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Autoscaling settings for a Modal Function deployed with Modal's Python
|
|
66
|
+
* client (`modal deploy`): warm containers, a container cap, buffer
|
|
67
|
+
* containers and scale-down timing, changed without redeploying the app.
|
|
68
|
+
*
|
|
69
|
+
* For a `Modal.Function` or `Modal.Server` of the Stack, set these on the
|
|
70
|
+
* resource itself. This resource adjusts a function deployed outside the
|
|
71
|
+
* Stack, and restores
|
|
72
|
+
* the settings it found when destroyed. Modal resets overrides like these
|
|
73
|
+
* when the app is redeployed, so redeploying the app and then this stack
|
|
74
|
+
* applies them again.
|
|
75
|
+
*
|
|
76
|
+
* ### Keeping containers warm
|
|
77
|
+
* **Example:** Two warm containers during business hours
|
|
78
|
+
* ```typescript
|
|
79
|
+
* import * as Modal from "@alchemy.run/modal";
|
|
80
|
+
*
|
|
81
|
+
* export const Warm = Modal.FunctionAutoscaler("Warm", {
|
|
82
|
+
* app: "inference",
|
|
83
|
+
* function: "Model.*",
|
|
84
|
+
* minContainers: 2,
|
|
85
|
+
* bufferContainers: 1,
|
|
86
|
+
* scaledownWindow: "5 minutes",
|
|
87
|
+
* });
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* @resource
|
|
91
|
+
* @product Function
|
|
92
|
+
*/
|
|
93
|
+
export const FunctionAutoscaler = declarable<FunctionAutoscaler>()(
|
|
94
|
+
Resource<FunctionAutoscaler>("Modal.FunctionAutoscaler"),
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
export type FunctionAutoscaler = Resource<
|
|
98
|
+
"Modal.FunctionAutoscaler",
|
|
99
|
+
FunctionAutoscalerProps,
|
|
100
|
+
FunctionAutoscalerAttributes,
|
|
101
|
+
never,
|
|
102
|
+
Providers
|
|
103
|
+
>;
|
|
104
|
+
|
|
105
|
+
const fromWire = (s: functions.AutoscalerSettings | undefined): AutoscalerSettingsState => ({
|
|
106
|
+
minContainers: s?.minContainers,
|
|
107
|
+
maxContainers: s?.maxContainers,
|
|
108
|
+
bufferContainers: s?.bufferContainers,
|
|
109
|
+
scaledownWindow: s?.scaledownWindow,
|
|
110
|
+
scaleupWindow: s?.scaleupWindow,
|
|
111
|
+
targetConcurrency: s?.targetConcurrency,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const toWire = (s: AutoscalerSettingsState): functions.AutoscalerSettings => ({
|
|
115
|
+
minContainers: s.minContainers,
|
|
116
|
+
maxContainers: s.maxContainers,
|
|
117
|
+
bufferContainers: s.bufferContainers,
|
|
118
|
+
scaledownWindow: s.scaledownWindow,
|
|
119
|
+
scaleupWindow: s.scaleupWindow,
|
|
120
|
+
targetConcurrency: s.targetConcurrency,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const desiredOf = (news: FunctionAutoscalerProps): AutoscalerSettingsState => ({
|
|
124
|
+
minContainers: news.minContainers,
|
|
125
|
+
maxContainers: news.maxContainers,
|
|
126
|
+
bufferContainers: news.bufferContainers,
|
|
127
|
+
scaledownWindow: seconds(news.scaledownWindow),
|
|
128
|
+
scaleupWindow: seconds(news.scaleupWindow),
|
|
129
|
+
targetConcurrency: news.targetConcurrency,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
export const FunctionAutoscalerProvider = () =>
|
|
133
|
+
Provider.effect(
|
|
134
|
+
FunctionAutoscaler,
|
|
135
|
+
Effect.gen(function* () {
|
|
136
|
+
const lookup = Effect.fn(function* (news: FunctionAutoscalerProps) {
|
|
137
|
+
const found = yield* functions
|
|
138
|
+
.getFunction({
|
|
139
|
+
appName: news.app,
|
|
140
|
+
objectTag: news.function,
|
|
141
|
+
environmentName: environmentOf(envNameOf(news.environment)),
|
|
142
|
+
})
|
|
143
|
+
.pipe(Effect.catchTag("FunctionNotFound", () => Effect.undefined));
|
|
144
|
+
return found?.functionId;
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const current = Effect.fn(function* (functionId: string) {
|
|
148
|
+
const { autoscalerConfiguration } = yield* functions.functionGetSchedulingParams({
|
|
149
|
+
functionId,
|
|
150
|
+
});
|
|
151
|
+
return autoscalerConfiguration;
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
stables: ["functionId", "original"],
|
|
156
|
+
diff: Effect.fn(function* ({ news, olds }) {
|
|
157
|
+
if (!isResolved(news)) return undefined;
|
|
158
|
+
if (
|
|
159
|
+
news.app !== olds?.app ||
|
|
160
|
+
news.function !== olds?.function ||
|
|
161
|
+
envNameOf(news.environment) !== envNameOf(olds?.environment)
|
|
162
|
+
) {
|
|
163
|
+
return { action: "replace" } as const;
|
|
164
|
+
}
|
|
165
|
+
return undefined;
|
|
166
|
+
}),
|
|
167
|
+
read: Effect.fn(function* ({ olds, output }) {
|
|
168
|
+
if (output === undefined || olds === undefined) return undefined;
|
|
169
|
+
const config = yield* current(output.functionId).pipe(
|
|
170
|
+
Effect.catchTag("FunctionNotFound", () => Effect.undefined),
|
|
171
|
+
);
|
|
172
|
+
if (!config) return undefined;
|
|
173
|
+
return { ...output, settings: fromWire(config.settings) };
|
|
174
|
+
}),
|
|
175
|
+
reconcile: Effect.fn(function* ({ news, output, session }) {
|
|
176
|
+
// Observe: the function (by name; its id changes on redeploy) and
|
|
177
|
+
// the settings in effect.
|
|
178
|
+
const functionId = yield* lookup(news);
|
|
179
|
+
if (!functionId) {
|
|
180
|
+
return yield* new FunctionAutoscalerUnexpectedResponse({
|
|
181
|
+
message: `Modal function ${news.app}.${news.function} isn't deployed${envNameOf(news.environment) ? ` in ${envNameOf(news.environment)}` : ""}`,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
const config = yield* current(functionId);
|
|
185
|
+
const observed = fromWire(config?.settings);
|
|
186
|
+
const original = output?.original ?? fromWire(config?.staticSettings ?? config?.settings);
|
|
187
|
+
// Sync only the settings that differ.
|
|
188
|
+
const desired = desiredOf(news);
|
|
189
|
+
const changed = (Object.keys(desired) as (keyof AutoscalerSettingsState)[]).some(
|
|
190
|
+
(key) => desired[key] !== undefined && desired[key] !== observed[key],
|
|
191
|
+
);
|
|
192
|
+
if (!changed) return { functionId, settings: observed, original };
|
|
193
|
+
yield* session.note(`Updating autoscaler of ${news.app}.${news.function}...`);
|
|
194
|
+
const { currentSettings } = yield* functions.functionUpdateSchedulingParams({
|
|
195
|
+
functionId,
|
|
196
|
+
settings: toWire(desired),
|
|
197
|
+
});
|
|
198
|
+
return { functionId, settings: fromWire(currentSettings), original };
|
|
199
|
+
}),
|
|
200
|
+
delete: Effect.fn(function* ({ output }) {
|
|
201
|
+
yield* functions
|
|
202
|
+
.functionUpdateSchedulingParams({
|
|
203
|
+
functionId: output.functionId,
|
|
204
|
+
settings: toWire(output.original),
|
|
205
|
+
})
|
|
206
|
+
.pipe(Effect.catchTag("FunctionNotFound", () => Effect.void));
|
|
207
|
+
}),
|
|
208
|
+
};
|
|
209
|
+
}),
|
|
210
|
+
);
|