@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/ImagePlan.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import * as BuildPlan from "@alchemy.run/docker/BuildPlan";
|
|
2
|
+
import * as DockerfileParser from "@alchemy.run/docker/DockerfileParser";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import type { ImageBuildSpec } from "./ImageBuild.ts";
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* Deploy-time image planning. Kept out of ImageBuild.ts because
|
|
8
|
+
* `@alchemy.run/docker/BuildPlan` imports the bundler, which must never
|
|
9
|
+
* reach a runtime bundle.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* What Modal's image builder runs. It isn't Docker: it ignores `USER`
|
|
14
|
+
* (containers run as root), doesn't implement `EXPOSE`, `HEALTHCHECK`,
|
|
15
|
+
* `LABEL`, `ONBUILD`, `STOPSIGNAL` or `VOLUME`, has no BuildKit mounts, and
|
|
16
|
+
* builds `linux/amd64` images. A Dockerfile outside this fails at plan with
|
|
17
|
+
* the offending lines.
|
|
18
|
+
*/
|
|
19
|
+
export const MODAL_CAPABILITIES: BuildPlan.Capabilities = {
|
|
20
|
+
target: "Modal.Image",
|
|
21
|
+
multiStage: false,
|
|
22
|
+
heredocs: false,
|
|
23
|
+
runMounts: false,
|
|
24
|
+
platforms: ["linux/amd64"],
|
|
25
|
+
instructions: {
|
|
26
|
+
USER: "ignored",
|
|
27
|
+
EXPOSE: "unsupported",
|
|
28
|
+
HEALTHCHECK: "unsupported",
|
|
29
|
+
LABEL: "unsupported",
|
|
30
|
+
ONBUILD: "unsupported",
|
|
31
|
+
STOPSIGNAL: "unsupported",
|
|
32
|
+
VOLUME: "unsupported",
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Lower a {@link BuildPlan.BuildPlan} to Modal's build inputs: the plan's
|
|
38
|
+
* Dockerfile as commands, every context file it reads, and its build args.
|
|
39
|
+
* `extra` lines (already checked) follow the plan's instructions.
|
|
40
|
+
*/
|
|
41
|
+
export const lowerPlan = Effect.fn(function* (
|
|
42
|
+
plan: BuildPlan.BuildPlan,
|
|
43
|
+
extra: ReadonlyArray<string> = [],
|
|
44
|
+
) {
|
|
45
|
+
const contextFiles = yield* Effect.forEach(plan.files, (file) =>
|
|
46
|
+
Effect.map(BuildPlan.readContextFile(file), (data) => ({
|
|
47
|
+
filename: file.path,
|
|
48
|
+
data,
|
|
49
|
+
mode: file.mode,
|
|
50
|
+
})),
|
|
51
|
+
);
|
|
52
|
+
return {
|
|
53
|
+
commands: [...BuildPlan.renderLines(plan), ...extra],
|
|
54
|
+
contextFiles,
|
|
55
|
+
buildArgs: plan.args,
|
|
56
|
+
} satisfies ImageBuildSpec;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Parse and check Dockerfile lines appended to a plan (`commands`), the way
|
|
61
|
+
* {@link BuildPlan.plan} checks the Dockerfile itself.
|
|
62
|
+
*/
|
|
63
|
+
export const checkCommands = Effect.fn(function* (commands: ReadonlyArray<string>) {
|
|
64
|
+
if (commands.length === 0) return [] as string[];
|
|
65
|
+
const parsed = yield* DockerfileParser.parse(`FROM scratch\n${commands.join("\n")}\n`);
|
|
66
|
+
const { violations } = BuildPlan.check(parsed, MODAL_CAPABILITIES, "linux/amd64");
|
|
67
|
+
if (violations.length > 0) {
|
|
68
|
+
return yield* new BuildPlan.UnsupportedDockerfile({
|
|
69
|
+
target: MODAL_CAPABILITIES.target,
|
|
70
|
+
violations,
|
|
71
|
+
message: [
|
|
72
|
+
`${MODAL_CAPABILITIES.target} cannot build these commands:`,
|
|
73
|
+
...violations.map((v) => ` ${v.instruction}: ${v.reason}`),
|
|
74
|
+
].join("\n"),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return DockerfileParser.renderLines(parsed).slice(1);
|
|
78
|
+
});
|
package/src/InferEnv.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type * as Effect from "effect/Effect";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The `process.env` an async `Modal.Sandbox` program sees: one string per
|
|
5
|
+
* `env` entry of the declaration.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* // alchemy.run.ts
|
|
10
|
+
* export const Agent = Modal.Sandbox("Agent", { main: "./src/agent.ts", app: Coder, env: { GREETING: "hi" } });
|
|
11
|
+
* export type AgentEnv = Modal.InferEnv<typeof Agent>;
|
|
12
|
+
*
|
|
13
|
+
* // src/agent.ts
|
|
14
|
+
* import type { AgentEnv } from "../alchemy.run.ts";
|
|
15
|
+
* const env = process.env as unknown as AgentEnv;
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export type InferEnv<F> =
|
|
19
|
+
F extends Effect.Effect<infer A, infer _E, infer _R>
|
|
20
|
+
? InferEnv<A>
|
|
21
|
+
: F extends { readonly Props: { readonly env?: infer E } }
|
|
22
|
+
? InferEnvRecord<Exclude<E, undefined>>
|
|
23
|
+
: InferEnvRecord<F>;
|
|
24
|
+
|
|
25
|
+
type InferEnvRecord<E> = {
|
|
26
|
+
readonly [K in keyof E]: string;
|
|
27
|
+
};
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import * as Binding from "alchemy/Binding";
|
|
2
|
+
import type { Input } from "alchemy/Input";
|
|
3
|
+
import type { Rpc } from "alchemy/Rpc";
|
|
4
|
+
import type { RuntimeContext } from "alchemy/RuntimeContext";
|
|
5
|
+
import * as Data from "effect/Data";
|
|
6
|
+
import type * as Effect from "effect/Effect";
|
|
7
|
+
import type { downloadBlob, uploadBlob } from "./Blob.ts";
|
|
8
|
+
import type { Function } from "./Function.ts";
|
|
9
|
+
import type { FunctionLookupError } from "./FunctionTarget.ts";
|
|
10
|
+
import type { ErrorOf, OpError } from "./internal.ts";
|
|
11
|
+
import type { InvokeOps } from "./InvokeFunctionHttp.ts";
|
|
12
|
+
|
|
13
|
+
/** A function deployed outside the Stack (`modal deploy`), by name. */
|
|
14
|
+
export interface FunctionRef {
|
|
15
|
+
/** Name of the deployed App (`modal deploy` / `modal.App("…")`). */
|
|
16
|
+
readonly app: string;
|
|
17
|
+
/** Function name in the App (`"embed"`), or `"Class.method"` for a class method. */
|
|
18
|
+
readonly function: string;
|
|
19
|
+
/** Environment the App is deployed in. @default the workspace default */
|
|
20
|
+
readonly environment?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Parameters of a parameterized class (`modal.parameter()` fields), for a
|
|
23
|
+
* `"Class.method"` target. Modal runs one set of containers per value set.
|
|
24
|
+
*/
|
|
25
|
+
readonly parameters?: Record<string, string | number | boolean | Uint8Array>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** What a function binding targets: a `Modal.Function` of the Stack, or a deployed function by name. */
|
|
29
|
+
export type FunctionTarget = Function | FunctionRef;
|
|
30
|
+
|
|
31
|
+
/** The function raised, or Modal failed the call. */
|
|
32
|
+
export class FunctionCallFailed extends Data.TaggedError("Modal.FunctionCallFailed")<{
|
|
33
|
+
readonly status: string;
|
|
34
|
+
readonly message: string;
|
|
35
|
+
readonly traceback?: string;
|
|
36
|
+
}> {}
|
|
37
|
+
|
|
38
|
+
/** Calling a function: looking it up, sending inputs, reading outputs, and the call's own failure. */
|
|
39
|
+
export type InvokeError =
|
|
40
|
+
| FunctionLookupError
|
|
41
|
+
| OpError<InvokeOps, "map" | "putInputs" | "getOutputs">
|
|
42
|
+
| ErrorOf<typeof uploadBlob | typeof downloadBlob>
|
|
43
|
+
| FunctionCallFailed
|
|
44
|
+
| FunctionCallTimeout;
|
|
45
|
+
|
|
46
|
+
/** The call didn't finish within its timeout. */
|
|
47
|
+
export class FunctionCallTimeout extends Data.TaggedError("Modal.FunctionCallTimeout")<{
|
|
48
|
+
readonly functionCallId: string;
|
|
49
|
+
readonly message: string;
|
|
50
|
+
}> {}
|
|
51
|
+
|
|
52
|
+
/** Options for one call. */
|
|
53
|
+
export interface CallOptions {
|
|
54
|
+
/** How long to wait for the result (seconds, or `"10 minutes"`). @default 300 seconds */
|
|
55
|
+
readonly timeout?: number | string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Call one function. Arguments and results travel as CBOR. */
|
|
59
|
+
export interface FunctionClient {
|
|
60
|
+
/** Call the function and wait for its result. */
|
|
61
|
+
call<A = unknown>(
|
|
62
|
+
args?: ReadonlyArray<unknown>,
|
|
63
|
+
kwargs?: Record<string, unknown>,
|
|
64
|
+
options?: CallOptions,
|
|
65
|
+
): Effect.Effect<A, InvokeError, RuntimeContext>;
|
|
66
|
+
/**
|
|
67
|
+
* Call the function once per input, in parallel across containers, and
|
|
68
|
+
* return the results in input order. Each input is a list of positional
|
|
69
|
+
* arguments. Fails with the first failed input.
|
|
70
|
+
*/
|
|
71
|
+
map<A = unknown>(
|
|
72
|
+
inputs: ReadonlyArray<ReadonlyArray<unknown>>,
|
|
73
|
+
options?: CallOptions,
|
|
74
|
+
): Effect.Effect<A[], InvokeError, RuntimeContext>;
|
|
75
|
+
/** Start a call without waiting; read it later with {@link result}. */
|
|
76
|
+
spawn(
|
|
77
|
+
args?: ReadonlyArray<unknown>,
|
|
78
|
+
kwargs?: Record<string, unknown>,
|
|
79
|
+
): Effect.Effect<{ readonly functionCallId: string }, InvokeError, RuntimeContext>;
|
|
80
|
+
/** The result of a spawned call, waiting up to `timeout`. */
|
|
81
|
+
result<A = unknown>(
|
|
82
|
+
call: { readonly functionCallId: string },
|
|
83
|
+
options?: CallOptions,
|
|
84
|
+
): Effect.Effect<A, InvokeError, RuntimeContext>;
|
|
85
|
+
/** Cancel a spawned call. */
|
|
86
|
+
cancel(call: {
|
|
87
|
+
readonly functionCallId: string;
|
|
88
|
+
}): Effect.Effect<void, FunctionLookupError | OpError<InvokeOps, "cancel">, RuntimeContext>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The RPC methods of a `Modal.Function` program: every function it returns
|
|
93
|
+
* besides `fetch` and `run`, called through Modal with the same arguments
|
|
94
|
+
* and results.
|
|
95
|
+
*/
|
|
96
|
+
export type FunctionStub<Shape> = Omit<Shape, "fetch" | "run">;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Call a Modal Function from any runtime: a Worker, a Lambda, a Durable
|
|
100
|
+
* Object, another Modal Function. Bind a `Modal.Function` of the Stack, or
|
|
101
|
+
* a function deployed with `modal deploy` by name.
|
|
102
|
+
*
|
|
103
|
+
* A `Modal.Function` program's RPC methods come back as a typed client:
|
|
104
|
+
* each call goes through Modal (queued, retried and autoscaled like any
|
|
105
|
+
* Modal call) to the method of that name. Arguments and results are JSON
|
|
106
|
+
* values, and a typed failure reaches the caller by its `_tag`. A method
|
|
107
|
+
* that returns a `Stream` arrives whole, once the call finishes. The
|
|
108
|
+
* binding gives the host its own key for the function, which every call
|
|
109
|
+
* carries: the program answers only callers bound to it.
|
|
110
|
+
*
|
|
111
|
+
* A Python function, or an async program, gets a {@link FunctionClient}
|
|
112
|
+
* instead: `call`, `map` and `spawn` with CBOR arguments (Modal's
|
|
113
|
+
* cross-language format). Payloads over 2 MiB go through Modal's blob store.
|
|
114
|
+
*
|
|
115
|
+
* ### Call a function
|
|
116
|
+
* **Example:** RPC methods of a `Modal.Function`
|
|
117
|
+
* ```typescript
|
|
118
|
+
* // src/Embed.ts
|
|
119
|
+
* import * as Modal from "@alchemy.run/modal";
|
|
120
|
+
* import * as Effect from "effect/Effect";
|
|
121
|
+
* import { Inference } from "./Inference.ts";
|
|
122
|
+
*
|
|
123
|
+
* export default class Embed extends Modal.Function<Embed>()(
|
|
124
|
+
* "Embed",
|
|
125
|
+
* { main: import.meta.url, app: Inference },
|
|
126
|
+
* Effect.gen(function* () {
|
|
127
|
+
* return {
|
|
128
|
+
* embed: Effect.fn(function* (text: string) {
|
|
129
|
+
* return { tokens: text.split(/\s+/).length };
|
|
130
|
+
* }),
|
|
131
|
+
* };
|
|
132
|
+
* }),
|
|
133
|
+
* ) {}
|
|
134
|
+
* ```
|
|
135
|
+
*
|
|
136
|
+
* **Example:** Call it from a Cloudflare Worker
|
|
137
|
+
* ```typescript
|
|
138
|
+
* import * as Cloudflare from "@alchemy.run/cloudflare";
|
|
139
|
+
* import * as Modal from "@alchemy.run/modal";
|
|
140
|
+
* import * as Effect from "effect/Effect";
|
|
141
|
+
* import * as HttpServerResponse from "effect/http/HttpServerResponse";
|
|
142
|
+
* import Embed from "./Embed.ts";
|
|
143
|
+
*
|
|
144
|
+
* export default class Api extends Cloudflare.Worker<Api>()(
|
|
145
|
+
* "Api",
|
|
146
|
+
* { main: import.meta.url, compatibility: { flags: ["nodejs_compat"] } },
|
|
147
|
+
* Effect.gen(function* () {
|
|
148
|
+
* const embed = yield* Modal.InvokeFunction(Embed);
|
|
149
|
+
* return {
|
|
150
|
+
* fetch: Effect.gen(function* () {
|
|
151
|
+
* const { tokens } = yield* embed.embed("hello world");
|
|
152
|
+
* return yield* HttpServerResponse.json({ tokens });
|
|
153
|
+
* }).pipe(Effect.orDie),
|
|
154
|
+
* };
|
|
155
|
+
* }).pipe(Effect.provide(Modal.InvokeFunctionHttp)),
|
|
156
|
+
* ) {}
|
|
157
|
+
* ```
|
|
158
|
+
*
|
|
159
|
+
* **Example:** A Python function deployed with `modal deploy`
|
|
160
|
+
* ```typescript
|
|
161
|
+
* const embed = yield* Modal.InvokeFunction({ app: "inference", function: "embed" });
|
|
162
|
+
* const vector = yield* embed.call<number[]>(["hello world"]);
|
|
163
|
+
* ```
|
|
164
|
+
*
|
|
165
|
+
* **Example:** A method of a parameterized Python class
|
|
166
|
+
* ```typescript
|
|
167
|
+
* const model = yield* Modal.InvokeFunction({
|
|
168
|
+
* app: "inference",
|
|
169
|
+
* function: "Model.generate",
|
|
170
|
+
* parameters: { size: "7b" },
|
|
171
|
+
* });
|
|
172
|
+
* const text = yield* model.call<string>(["hello"]);
|
|
173
|
+
* ```
|
|
174
|
+
*
|
|
175
|
+
* ### Fan out
|
|
176
|
+
* **Example:** One call per input, in parallel
|
|
177
|
+
* ```typescript
|
|
178
|
+
* const results = yield* embed.map<{ tokens: number }>([["a"], ["b"], ["c"]]);
|
|
179
|
+
* ```
|
|
180
|
+
*
|
|
181
|
+
* ### Fire and forget
|
|
182
|
+
* **Example:** Spawn, then read the result later
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const job = yield* train.spawn([], { epochs: 3 });
|
|
185
|
+
* const metrics = yield* train.result(job, { timeout: "30 minutes" });
|
|
186
|
+
* ```
|
|
187
|
+
*
|
|
188
|
+
* @binding
|
|
189
|
+
* @product Function
|
|
190
|
+
*/
|
|
191
|
+
export interface InvokeFunction extends Binding.Service<
|
|
192
|
+
InvokeFunction,
|
|
193
|
+
"Modal.InvokeFunction",
|
|
194
|
+
(target: FunctionTarget) => Effect.Effect<FunctionClient>
|
|
195
|
+
> {}
|
|
196
|
+
|
|
197
|
+
/** InvokeFunction's call signatures, typed from the target's program. */
|
|
198
|
+
export interface InvokeFunctionCall {
|
|
199
|
+
/** A `Modal.Function` of the Stack whose program has RPC methods: its typed client. */
|
|
200
|
+
<Shape, Req = never>(
|
|
201
|
+
target: (Function & Rpc<Shape>) | Effect.Effect<Function & Rpc<Shape>, never, Req>,
|
|
202
|
+
): Effect.Effect<FunctionStub<Shape>, never, InvokeFunction | Req>;
|
|
203
|
+
/** A deployed function by name, or an async program: `call`, `map` and `spawn`. */
|
|
204
|
+
<Req = never>(
|
|
205
|
+
target: Input<FunctionTarget> | Effect.Effect<FunctionTarget, never, Req>,
|
|
206
|
+
): Effect.Effect<FunctionClient, never, InvokeFunction | Req>;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export const InvokeFunction = Binding.Service<InvokeFunction>(
|
|
210
|
+
"Modal.InvokeFunction",
|
|
211
|
+
) as unknown as InvokeFunctionCall & InvokeFunction;
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import * as functions from "@distilled.cloud/modal/functions";
|
|
2
|
+
import {
|
|
3
|
+
asEffectOrStream,
|
|
4
|
+
decodeRpcResponseStream,
|
|
5
|
+
decodeRpcResult,
|
|
6
|
+
RpcCallError,
|
|
7
|
+
} from "alchemy/Rpc";
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import * as Layer from "effect/Layer";
|
|
10
|
+
import * as Stream from "effect/Stream";
|
|
11
|
+
import { BlobOps, downloadBlob, MAX_INLINE_BYTES, uploadBlob } from "./Blob.ts";
|
|
12
|
+
import { decodeCbor, encodeCbor } from "./Cbor.ts";
|
|
13
|
+
import { isFunctionRef, makeFunctionBinding, type ResolvedFunction } from "./FunctionTarget.ts";
|
|
14
|
+
import { operations, seconds } from "./internal.ts";
|
|
15
|
+
import { RPC_STREAM_KEY } from "./internal/Entrypoint.ts";
|
|
16
|
+
import { RPC_KEY_KWARG, RpcCaller } from "./internal/RpcAuth.ts";
|
|
17
|
+
import {
|
|
18
|
+
FunctionCallFailed,
|
|
19
|
+
FunctionCallTimeout,
|
|
20
|
+
InvokeFunction,
|
|
21
|
+
type CallOptions,
|
|
22
|
+
type FunctionClient,
|
|
23
|
+
type FunctionTarget,
|
|
24
|
+
} from "./InvokeFunction.ts";
|
|
25
|
+
|
|
26
|
+
/** The operations the client calls, resolved by `ModalBindings.withCredentials`. */
|
|
27
|
+
const InvokeOps = operations({
|
|
28
|
+
map: functions.functionMap,
|
|
29
|
+
putInputs: functions.functionPutInputs,
|
|
30
|
+
getOutputs: functions.getFunctionOutputs,
|
|
31
|
+
cancel: functions.cancelFunctionCall,
|
|
32
|
+
blobs: BlobOps,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export type InvokeOps = Effect.Success<typeof InvokeOps>;
|
|
36
|
+
|
|
37
|
+
/** One input: CBOR `[args, kwargs]`, inline or (over 2 MiB) as a blob. */
|
|
38
|
+
const encodeInput = Effect.fn(function* (
|
|
39
|
+
blobs: BlobOps,
|
|
40
|
+
args: ReadonlyArray<unknown>,
|
|
41
|
+
kwargs: Record<string, unknown>,
|
|
42
|
+
method: string | undefined,
|
|
43
|
+
) {
|
|
44
|
+
const bytes = yield* Effect.try({
|
|
45
|
+
try: () => encodeCbor([args, kwargs]),
|
|
46
|
+
catch: (cause) =>
|
|
47
|
+
new FunctionCallFailed({
|
|
48
|
+
status: "INVALID_ARGUMENTS",
|
|
49
|
+
message: `Arguments aren't CBOR-encodable: ${String(cause)}`,
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
52
|
+
const payload =
|
|
53
|
+
bytes.length > MAX_INLINE_BYTES
|
|
54
|
+
? { argsBlobId: yield* uploadBlob(blobs, bytes) }
|
|
55
|
+
: { args: yield* Effect.sync(() => Buffer.from(bytes).toString("base64")) };
|
|
56
|
+
return {
|
|
57
|
+
...payload,
|
|
58
|
+
dataFormat: "DATA_FORMAT_CBOR",
|
|
59
|
+
methodName: method,
|
|
60
|
+
} satisfies functions.FunctionInput;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
/** The value of a finished output, or its failure. */
|
|
64
|
+
const decodeOutput = Effect.fn(function* (
|
|
65
|
+
blobs: BlobOps,
|
|
66
|
+
functionCallId: string,
|
|
67
|
+
output: functions.GetFunctionOutputsItem,
|
|
68
|
+
) {
|
|
69
|
+
const result = output.result;
|
|
70
|
+
if (result?.status !== "GENERIC_STATUS_SUCCESS") {
|
|
71
|
+
return yield* new FunctionCallFailed({
|
|
72
|
+
status: result?.status ?? "GENERIC_STATUS_UNSPECIFIED",
|
|
73
|
+
message: result?.exception || `Function call ${functionCallId} failed`,
|
|
74
|
+
traceback: result?.traceback,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const bytes = result.dataBlobId
|
|
78
|
+
? yield* downloadBlob(blobs, result.dataBlobId)
|
|
79
|
+
: result.data
|
|
80
|
+
? yield* Effect.sync(() => new Uint8Array(Buffer.from(result.data!, "base64")))
|
|
81
|
+
: undefined;
|
|
82
|
+
if (bytes === undefined) return null;
|
|
83
|
+
return yield* Effect.try({
|
|
84
|
+
try: () => decodeCbor(bytes),
|
|
85
|
+
catch: (cause) =>
|
|
86
|
+
new FunctionCallFailed({
|
|
87
|
+
status: "INVALID_RESULT",
|
|
88
|
+
message: `The result isn't CBOR (return plain values, or set the function's serialization): ${String(cause)}`,
|
|
89
|
+
}),
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
/** Inputs per `FunctionPutInputs` request. */
|
|
94
|
+
const BATCH = 49;
|
|
95
|
+
|
|
96
|
+
/** A client for a resolved function. */
|
|
97
|
+
export const makeFunctionClient = (resolved: ResolvedFunction, ops: InvokeOps): FunctionClient => {
|
|
98
|
+
const { functionId, method } = resolved;
|
|
99
|
+
|
|
100
|
+
/** Collect `count` outputs of a call, by input index. */
|
|
101
|
+
const collect = Effect.fn(function* (
|
|
102
|
+
functionCallId: string,
|
|
103
|
+
count: number,
|
|
104
|
+
timeout: number | string | undefined,
|
|
105
|
+
) {
|
|
106
|
+
const budget = seconds(timeout) ?? 300;
|
|
107
|
+
const rounds = Math.max(1, Math.ceil(budget / 55));
|
|
108
|
+
const values = new Map<number, unknown>();
|
|
109
|
+
let lastEntryId = "0-0";
|
|
110
|
+
for (let round = 0; round < rounds && values.size < count; round++) {
|
|
111
|
+
const response = yield* ops.getOutputs({
|
|
112
|
+
functionCallId,
|
|
113
|
+
maxValues: Math.min(1000, count - values.size),
|
|
114
|
+
timeout: Math.min(55, budget),
|
|
115
|
+
lastEntryId,
|
|
116
|
+
// A map's outputs stay until all are read; a single output is popped.
|
|
117
|
+
clearOnSuccess: count === 1,
|
|
118
|
+
});
|
|
119
|
+
if (response.lastEntryId) lastEntryId = response.lastEntryId;
|
|
120
|
+
for (const output of response.outputs ?? []) {
|
|
121
|
+
if (!output.result) continue;
|
|
122
|
+
values.set(output.idx ?? 0, yield* decodeOutput(ops.blobs, functionCallId, output));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (values.size < count) {
|
|
126
|
+
return yield* new FunctionCallTimeout({
|
|
127
|
+
functionCallId,
|
|
128
|
+
message: `Function call ${functionCallId} didn't finish within ${budget} seconds`,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return Array.from({ length: count }, (_, idx) => values.get(idx));
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Start a function call the way Modal's clients do: a unary call sends its
|
|
136
|
+
* input with `FunctionMap` (or with `FunctionPutInputs` when Modal doesn't
|
|
137
|
+
* take it there); a map creates the call, then sends every input with
|
|
138
|
+
* `FunctionPutInputs`.
|
|
139
|
+
*/
|
|
140
|
+
const start = Effect.fn(function* (
|
|
141
|
+
inputs: ReadonlyArray<readonly [ReadonlyArray<unknown>, Record<string, unknown>]>,
|
|
142
|
+
type: "FUNCTION_CALL_TYPE_UNARY" | "FUNCTION_CALL_TYPE_MAP",
|
|
143
|
+
invocation: "FUNCTION_CALL_INVOCATION_TYPE_SYNC" | "FUNCTION_CALL_INVOCATION_TYPE_ASYNC",
|
|
144
|
+
) {
|
|
145
|
+
const id = yield* functionId;
|
|
146
|
+
const items = yield* Effect.forEach(inputs, ([args, kwargs], idx) =>
|
|
147
|
+
Effect.map(encodeInput(ops.blobs, args, kwargs, method), (input) => ({ idx, input })),
|
|
148
|
+
);
|
|
149
|
+
const unary = type === "FUNCTION_CALL_TYPE_UNARY";
|
|
150
|
+
const response = yield* ops.map({
|
|
151
|
+
functionId: id,
|
|
152
|
+
functionCallType: type,
|
|
153
|
+
functionCallInvocationType: invocation,
|
|
154
|
+
returnExceptions: false,
|
|
155
|
+
pipelinedInputs: unary ? items : undefined,
|
|
156
|
+
});
|
|
157
|
+
const functionCallId = response.functionCallId ?? "";
|
|
158
|
+
const sent = unary && (response.pipelinedInputs ?? []).length > 0 ? items.length : 0;
|
|
159
|
+
for (let offset = sent; offset < items.length; offset += BATCH) {
|
|
160
|
+
yield* ops.putInputs({
|
|
161
|
+
functionId: id,
|
|
162
|
+
functionCallId,
|
|
163
|
+
inputs: items.slice(offset, offset + BATCH),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return functionCallId;
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
call: <A>(
|
|
171
|
+
args: ReadonlyArray<unknown> = [],
|
|
172
|
+
kwargs: Record<string, unknown> = {},
|
|
173
|
+
options: CallOptions = {},
|
|
174
|
+
) =>
|
|
175
|
+
start(
|
|
176
|
+
[[args, kwargs]],
|
|
177
|
+
"FUNCTION_CALL_TYPE_UNARY",
|
|
178
|
+
"FUNCTION_CALL_INVOCATION_TYPE_SYNC",
|
|
179
|
+
).pipe(
|
|
180
|
+
Effect.flatMap((id) => collect(id, 1, options.timeout)),
|
|
181
|
+
// CBOR results are untyped; the caller names the shape it expects.
|
|
182
|
+
Effect.map(([value]) => value as A),
|
|
183
|
+
),
|
|
184
|
+
map: <A>(inputs: ReadonlyArray<ReadonlyArray<unknown>>, options: CallOptions = {}) =>
|
|
185
|
+
inputs.length === 0
|
|
186
|
+
? Effect.succeed([] as A[])
|
|
187
|
+
: start(
|
|
188
|
+
inputs.map((args) => [args, {}] as const),
|
|
189
|
+
"FUNCTION_CALL_TYPE_MAP",
|
|
190
|
+
"FUNCTION_CALL_INVOCATION_TYPE_SYNC",
|
|
191
|
+
).pipe(
|
|
192
|
+
Effect.flatMap((id) => collect(id, inputs.length, options.timeout)),
|
|
193
|
+
Effect.map((values) => values as A[]),
|
|
194
|
+
),
|
|
195
|
+
spawn: (args = [], kwargs = {}) =>
|
|
196
|
+
start(
|
|
197
|
+
[[args, kwargs]],
|
|
198
|
+
"FUNCTION_CALL_TYPE_UNARY",
|
|
199
|
+
"FUNCTION_CALL_INVOCATION_TYPE_ASYNC",
|
|
200
|
+
).pipe(Effect.map((functionCallId) => ({ functionCallId }))),
|
|
201
|
+
result: <A>(call: { readonly functionCallId: string }, options: CallOptions = {}) =>
|
|
202
|
+
collect(call.functionCallId, 1, options.timeout).pipe(Effect.map(([value]) => value as A)),
|
|
203
|
+
cancel: (call) =>
|
|
204
|
+
ops.cancel({ functionCallId: call.functionCallId }).pipe(
|
|
205
|
+
Effect.catchTag("FunctionCallNotFound", () => Effect.void),
|
|
206
|
+
Effect.asVoid,
|
|
207
|
+
),
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
/** Whether a call's result is a streamed RPC result (see `RPC_STREAM_KEY`). */
|
|
212
|
+
const isStreamResult = (value: unknown): value is { [RPC_STREAM_KEY]: unknown[] } =>
|
|
213
|
+
typeof value === "object" &&
|
|
214
|
+
value !== null &&
|
|
215
|
+
Array.isArray((value as Record<string, unknown>)[RPC_STREAM_KEY]);
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* The typed client of a `Modal.Function` program's RPC methods. Each method
|
|
219
|
+
* is a call to the function's method of that name; its result is the
|
|
220
|
+
* program's JSON answer, a failure envelope the call fails with, or a
|
|
221
|
+
* stream's values. A Function without methods (an async program) keeps
|
|
222
|
+
* the {@link FunctionClient} operations.
|
|
223
|
+
*/
|
|
224
|
+
export const makeRpcClient = (
|
|
225
|
+
resolved: ResolvedFunction,
|
|
226
|
+
ops: InvokeOps,
|
|
227
|
+
methods: Effect.Effect<ReadonlyArray<string> | undefined>,
|
|
228
|
+
key: Effect.Effect<string | undefined>,
|
|
229
|
+
): Record<string, unknown> => {
|
|
230
|
+
const client = makeFunctionClient(resolved, ops);
|
|
231
|
+
const callMethod = (name: string, args: ReadonlyArray<unknown>) =>
|
|
232
|
+
key.pipe(
|
|
233
|
+
Effect.flatMap((value) =>
|
|
234
|
+
makeFunctionClient({ ...resolved, method: name }, ops).call(
|
|
235
|
+
args,
|
|
236
|
+
// The binding's key: the program serves only callers it issued keys to.
|
|
237
|
+
value === undefined ? {} : { [RPC_KEY_KWARG]: value },
|
|
238
|
+
),
|
|
239
|
+
),
|
|
240
|
+
Effect.flatMap((value) =>
|
|
241
|
+
isStreamResult(value)
|
|
242
|
+
? // The stream's values, re-encoded as the NDJSON the RPC codec
|
|
243
|
+
// decodes (byte chunks and a trailing failure marker included).
|
|
244
|
+
Effect.succeed(
|
|
245
|
+
Stream.fromIterable(value[RPC_STREAM_KEY]).pipe(
|
|
246
|
+
Stream.map((item) => `${JSON.stringify(item)}\n`),
|
|
247
|
+
Stream.encodeText,
|
|
248
|
+
decodeRpcResponseStream,
|
|
249
|
+
),
|
|
250
|
+
)
|
|
251
|
+
: decodeRpcResult(value),
|
|
252
|
+
),
|
|
253
|
+
);
|
|
254
|
+
return new Proxy(
|
|
255
|
+
{},
|
|
256
|
+
{
|
|
257
|
+
get: (_, prop) => {
|
|
258
|
+
// Never thenable, and no symbol members.
|
|
259
|
+
if (typeof prop !== "string" || prop === "then") return undefined;
|
|
260
|
+
const call = (args: unknown[]) =>
|
|
261
|
+
Effect.gen(function* () {
|
|
262
|
+
const names = (yield* methods) ?? [];
|
|
263
|
+
if (names.includes(prop)) return yield* callMethod(prop, args);
|
|
264
|
+
const operation = (client as unknown as Record<string, unknown>)[prop];
|
|
265
|
+
if (typeof operation === "function") {
|
|
266
|
+
return yield* (operation as (...a: unknown[]) => Effect.Effect<unknown, unknown>)(
|
|
267
|
+
...args,
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
return yield* new RpcCallError({
|
|
271
|
+
method: prop,
|
|
272
|
+
cause: `The function has no RPC method ${prop}`,
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
return (...args: unknown[]) =>
|
|
276
|
+
asEffectOrStream(
|
|
277
|
+
// oxlint-disable-next-line effecttsgo/unsafe-effect-type-assertion -- the stub's declared method types carry `RuntimeContext`, which the caller's runtime provides
|
|
278
|
+
call(args) as Effect.Effect<unknown, unknown>,
|
|
279
|
+
);
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
);
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* {@link InvokeFunction} over Modal's API. Grants the host's identity (a scoped
|
|
287
|
+
* `Modal.ServiceUser`) the `contributor` role on the function's environment.
|
|
288
|
+
*
|
|
289
|
+
* @layer
|
|
290
|
+
* @product Function
|
|
291
|
+
* @provides Modal.InvokeFunction
|
|
292
|
+
*/
|
|
293
|
+
export const InvokeFunctionHttp = Layer.effect(
|
|
294
|
+
InvokeFunction,
|
|
295
|
+
Effect.gen(function* () {
|
|
296
|
+
const caller = yield* RpcCaller;
|
|
297
|
+
return yield* makeFunctionBinding({
|
|
298
|
+
tag: "Modal.InvokeFunction",
|
|
299
|
+
operations: InvokeOps,
|
|
300
|
+
role: "contributor",
|
|
301
|
+
make: Effect.fn(function* (resolved, ops, target: FunctionTarget) {
|
|
302
|
+
if (isFunctionRef(target)) return makeFunctionClient(resolved, ops);
|
|
303
|
+
// This host's key for the Function's RPC methods (minted at deploy).
|
|
304
|
+
const key = yield* caller(target as unknown as { readonly LogicalId: string });
|
|
305
|
+
// The program's methods, recorded at deploy (an attribute of the Function).
|
|
306
|
+
const methods = yield* (
|
|
307
|
+
target as unknown as {
|
|
308
|
+
readonly methods: Effect.Effect<Effect.Effect<ReadonlyArray<string> | undefined>>;
|
|
309
|
+
}
|
|
310
|
+
).methods;
|
|
311
|
+
// Typed by `InvokeFunction`'s call signatures from the target's program.
|
|
312
|
+
return makeRpcClient(resolved, ops, methods, key) as unknown as FunctionClient;
|
|
313
|
+
}),
|
|
314
|
+
});
|
|
315
|
+
}),
|
|
316
|
+
);
|