@alchemy.run/modal 0.0.0 → 2.0.0-beta.87
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +96 -4
- package/lib/App.d.ts +143 -0
- package/lib/App.d.ts.map +1 -0
- package/lib/App.js +198 -0
- package/lib/App.js.map +1 -0
- package/lib/AuthProvider.d.ts +53 -0
- package/lib/AuthProvider.d.ts.map +1 -0
- package/lib/AuthProvider.js +209 -0
- package/lib/AuthProvider.js.map +1 -0
- package/lib/BindingHttp.d.ts +56 -0
- package/lib/BindingHttp.d.ts.map +1 -0
- package/lib/BindingHttp.js +50 -0
- package/lib/BindingHttp.js.map +1 -0
- package/lib/Blob.d.ts +34 -0
- package/lib/Blob.d.ts.map +1 -0
- package/lib/Blob.js +59 -0
- package/lib/Blob.js.map +1 -0
- package/lib/Bootstrap.d.ts +8 -0
- package/lib/Bootstrap.d.ts.map +1 -0
- package/lib/Bootstrap.js +26 -0
- package/lib/Bootstrap.js.map +1 -0
- package/lib/Cbor.d.ts +10 -0
- package/lib/Cbor.d.ts.map +1 -0
- package/lib/Cbor.js +177 -0
- package/lib/Cbor.js.map +1 -0
- package/lib/ConnectSandbox.d.ts +64 -0
- package/lib/ConnectSandbox.d.ts.map +1 -0
- package/lib/ConnectSandbox.js +33 -0
- package/lib/ConnectSandbox.js.map +1 -0
- package/lib/Container.d.ts +124 -0
- package/lib/Container.d.ts.map +1 -0
- package/lib/Container.js +1 -0
- package/lib/Container.js.map +1 -0
- package/lib/Contributions.d.ts +7 -0
- package/lib/Contributions.d.ts.map +1 -0
- package/lib/Contributions.js +6 -0
- package/lib/Contributions.js.map +1 -0
- package/lib/CreateDict.d.ts +83 -0
- package/lib/CreateDict.d.ts.map +1 -0
- package/lib/CreateDict.js +3 -0
- package/lib/CreateDict.js.map +1 -0
- package/lib/CreateDictHttp.d.ts +33 -0
- package/lib/CreateDictHttp.d.ts.map +1 -0
- package/lib/CreateDictHttp.js +67 -0
- package/lib/CreateDictHttp.js.map +1 -0
- package/lib/CreateImage.d.ts +98 -0
- package/lib/CreateImage.d.ts.map +1 -0
- package/lib/CreateImage.js +3 -0
- package/lib/CreateImage.js.map +1 -0
- package/lib/CreateImageHttp.d.ts +51 -0
- package/lib/CreateImageHttp.d.ts.map +1 -0
- package/lib/CreateImageHttp.js +87 -0
- package/lib/CreateImageHttp.js.map +1 -0
- package/lib/CreateQueue.d.ts +83 -0
- package/lib/CreateQueue.d.ts.map +1 -0
- package/lib/CreateQueue.js +3 -0
- package/lib/CreateQueue.js.map +1 -0
- package/lib/CreateQueueHttp.d.ts +31 -0
- package/lib/CreateQueueHttp.d.ts.map +1 -0
- package/lib/CreateQueueHttp.js +67 -0
- package/lib/CreateQueueHttp.js.map +1 -0
- package/lib/CreateSandbox.d.ts +186 -0
- package/lib/CreateSandbox.d.ts.map +1 -0
- package/lib/CreateSandbox.js +3 -0
- package/lib/CreateSandbox.js.map +1 -0
- package/lib/CreateSandboxHttp.d.ts +17 -0
- package/lib/CreateSandboxHttp.d.ts.map +1 -0
- package/lib/CreateSandboxHttp.js +117 -0
- package/lib/CreateSandboxHttp.js.map +1 -0
- package/lib/CreateSecret.d.ts +95 -0
- package/lib/CreateSecret.d.ts.map +1 -0
- package/lib/CreateSecret.js +3 -0
- package/lib/CreateSecret.js.map +1 -0
- package/lib/CreateSecretHttp.d.ts +24 -0
- package/lib/CreateSecretHttp.d.ts.map +1 -0
- package/lib/CreateSecretHttp.js +60 -0
- package/lib/CreateSecretHttp.js.map +1 -0
- package/lib/CreateVolume.d.ts +84 -0
- package/lib/CreateVolume.d.ts.map +1 -0
- package/lib/CreateVolume.js +3 -0
- package/lib/CreateVolume.js.map +1 -0
- package/lib/CreateVolumeHttp.d.ts +32 -0
- package/lib/CreateVolumeHttp.d.ts.map +1 -0
- package/lib/CreateVolumeHttp.js +69 -0
- package/lib/CreateVolumeHttp.js.map +1 -0
- package/lib/Credentials.d.ts +32 -0
- package/lib/Credentials.d.ts.map +1 -0
- package/lib/Credentials.js +44 -0
- package/lib/Credentials.js.map +1 -0
- package/lib/Dict.d.ts +147 -0
- package/lib/Dict.d.ts.map +1 -0
- package/lib/Dict.js +175 -0
- package/lib/Dict.js.map +1 -0
- package/lib/DictClient.d.ts +55 -0
- package/lib/DictClient.d.ts.map +1 -0
- package/lib/DictClient.js +89 -0
- package/lib/DictClient.js.map +1 -0
- package/lib/Domain.d.ts +86 -0
- package/lib/Domain.d.ts.map +1 -0
- package/lib/Domain.js +113 -0
- package/lib/Domain.js.map +1 -0
- package/lib/Endpoint.d.ts +181 -0
- package/lib/Endpoint.d.ts.map +1 -0
- package/lib/Endpoint.js +283 -0
- package/lib/Endpoint.js.map +1 -0
- package/lib/Environment.d.ts +174 -0
- package/lib/Environment.d.ts.map +1 -0
- package/lib/Environment.js +244 -0
- package/lib/Environment.js.map +1 -0
- package/lib/FetchServer.d.ts +105 -0
- package/lib/FetchServer.d.ts.map +1 -0
- package/lib/FetchServer.js +3 -0
- package/lib/FetchServer.js.map +1 -0
- package/lib/FetchServerHttp.d.ts +21 -0
- package/lib/FetchServerHttp.d.ts.map +1 -0
- package/lib/FetchServerHttp.js +84 -0
- package/lib/FetchServerHttp.js.map +1 -0
- package/lib/Function.d.ts +236 -0
- package/lib/Function.d.ts.map +1 -0
- package/lib/Function.js +273 -0
- package/lib/Function.js.map +1 -0
- package/lib/FunctionAutoscaler.d.ts +99 -0
- package/lib/FunctionAutoscaler.d.ts.map +1 -0
- package/lib/FunctionAutoscaler.js +136 -0
- package/lib/FunctionAutoscaler.js.map +1 -0
- package/lib/FunctionTarget.d.ts +61 -0
- package/lib/FunctionTarget.d.ts.map +1 -0
- package/lib/FunctionTarget.js +136 -0
- package/lib/FunctionTarget.js.map +1 -0
- package/lib/Image.d.ts +159 -0
- package/lib/Image.d.ts.map +1 -0
- package/lib/Image.js +203 -0
- package/lib/Image.js.map +1 -0
- package/lib/ImageBuild.d.ts +108 -0
- package/lib/ImageBuild.d.ts.map +1 -0
- package/lib/ImageBuild.js +157 -0
- package/lib/ImageBuild.js.map +1 -0
- package/lib/ImagePlan.d.ts +31 -0
- package/lib/ImagePlan.d.ts.map +1 -0
- package/lib/ImagePlan.js +70 -0
- package/lib/ImagePlan.js.map +1 -0
- package/lib/InferEnv.d.ts +26 -0
- package/lib/InferEnv.d.ts.map +1 -0
- package/lib/InferEnv.js +1 -0
- package/lib/InferEnv.js.map +1 -0
- package/lib/InvokeFunction.d.ts +186 -0
- package/lib/InvokeFunction.d.ts.map +1 -0
- package/lib/InvokeFunction.js +10 -0
- package/lib/InvokeFunction.js.map +1 -0
- package/lib/InvokeFunctionHttp.d.ts +39 -0
- package/lib/InvokeFunctionHttp.d.ts.map +1 -0
- package/lib/InvokeFunctionHttp.js +210 -0
- package/lib/InvokeFunctionHttp.js.map +1 -0
- package/lib/ModalBindings.d.ts +138 -0
- package/lib/ModalBindings.d.ts.map +1 -0
- package/lib/ModalBindings.js +223 -0
- package/lib/ModalBindings.js.map +1 -0
- package/lib/MountBucket.d.ts +80 -0
- package/lib/MountBucket.d.ts.map +1 -0
- package/lib/MountBucket.js +44 -0
- package/lib/MountBucket.js.map +1 -0
- package/lib/MountVolume.d.ts +77 -0
- package/lib/MountVolume.d.ts.map +1 -0
- package/lib/MountVolume.js +41 -0
- package/lib/MountVolume.js.map +1 -0
- package/lib/Mounts.d.ts +134 -0
- package/lib/Mounts.d.ts.map +1 -0
- package/lib/Mounts.js +87 -0
- package/lib/Mounts.js.map +1 -0
- package/lib/PersistentSandbox.d.ts +75 -0
- package/lib/PersistentSandbox.d.ts.map +1 -0
- package/lib/PersistentSandbox.js +93 -0
- package/lib/PersistentSandbox.js.map +1 -0
- package/lib/Providers.d.ts +23 -0
- package/lib/Providers.d.ts.map +1 -0
- package/lib/Providers.js +64 -0
- package/lib/Providers.js.map +1 -0
- package/lib/Proxy.d.ts +94 -0
- package/lib/Proxy.d.ts.map +1 -0
- package/lib/Proxy.js +132 -0
- package/lib/Proxy.js.map +1 -0
- package/lib/Queue.d.ts +147 -0
- package/lib/Queue.d.ts.map +1 -0
- package/lib/Queue.js +177 -0
- package/lib/Queue.js.map +1 -0
- package/lib/QueueClient.d.ts +64 -0
- package/lib/QueueClient.d.ts.map +1 -0
- package/lib/QueueClient.js +73 -0
- package/lib/QueueClient.js.map +1 -0
- package/lib/ReadApp.d.ts +85 -0
- package/lib/ReadApp.d.ts.map +1 -0
- package/lib/ReadApp.js +3 -0
- package/lib/ReadApp.js.map +1 -0
- package/lib/ReadAppHttp.d.ts +26 -0
- package/lib/ReadAppHttp.d.ts.map +1 -0
- package/lib/ReadAppHttp.js +106 -0
- package/lib/ReadAppHttp.js.map +1 -0
- package/lib/ReadDict.d.ts +39 -0
- package/lib/ReadDict.d.ts.map +1 -0
- package/lib/ReadDict.js +3 -0
- package/lib/ReadDict.js.map +1 -0
- package/lib/ReadDictHttp.d.ts +12 -0
- package/lib/ReadDictHttp.d.ts.map +1 -0
- package/lib/ReadDictHttp.js +23 -0
- package/lib/ReadDictHttp.js.map +1 -0
- package/lib/ReadFunction.d.ts +73 -0
- package/lib/ReadFunction.d.ts.map +1 -0
- package/lib/ReadFunction.js +3 -0
- package/lib/ReadFunction.js.map +1 -0
- package/lib/ReadFunctionHttp.d.ts +25 -0
- package/lib/ReadFunctionHttp.d.ts.map +1 -0
- package/lib/ReadFunctionHttp.js +63 -0
- package/lib/ReadFunctionHttp.js.map +1 -0
- package/lib/ReadQueue.d.ts +39 -0
- package/lib/ReadQueue.d.ts.map +1 -0
- package/lib/ReadQueue.js +3 -0
- package/lib/ReadQueue.js.map +1 -0
- package/lib/ReadQueueHttp.d.ts +12 -0
- package/lib/ReadQueueHttp.d.ts.map +1 -0
- package/lib/ReadQueueHttp.js +23 -0
- package/lib/ReadQueueHttp.js.map +1 -0
- package/lib/ReadServer.d.ts +72 -0
- package/lib/ReadServer.d.ts.map +1 -0
- package/lib/ReadServer.js +3 -0
- package/lib/ReadServer.js.map +1 -0
- package/lib/ReadServerHttp.d.ts +25 -0
- package/lib/ReadServerHttp.d.ts.map +1 -0
- package/lib/ReadServerHttp.js +70 -0
- package/lib/ReadServerHttp.js.map +1 -0
- package/lib/ReadVolume.d.ts +40 -0
- package/lib/ReadVolume.d.ts.map +1 -0
- package/lib/ReadVolume.js +3 -0
- package/lib/ReadVolume.js.map +1 -0
- package/lib/ReadVolumeHttp.d.ts +12 -0
- package/lib/ReadVolumeHttp.d.ts.map +1 -0
- package/lib/ReadVolumeHttp.js +24 -0
- package/lib/ReadVolumeHttp.js.map +1 -0
- package/lib/ReadWriteDict.d.ts +39 -0
- package/lib/ReadWriteDict.d.ts.map +1 -0
- package/lib/ReadWriteDict.js +3 -0
- package/lib/ReadWriteDict.js.map +1 -0
- package/lib/ReadWriteDictHttp.d.ts +12 -0
- package/lib/ReadWriteDictHttp.d.ts.map +1 -0
- package/lib/ReadWriteDictHttp.js +23 -0
- package/lib/ReadWriteDictHttp.js.map +1 -0
- package/lib/ReadWriteQueue.d.ts +40 -0
- package/lib/ReadWriteQueue.d.ts.map +1 -0
- package/lib/ReadWriteQueue.js +3 -0
- package/lib/ReadWriteQueue.js.map +1 -0
- package/lib/ReadWriteQueueHttp.d.ts +12 -0
- package/lib/ReadWriteQueueHttp.d.ts.map +1 -0
- package/lib/ReadWriteQueueHttp.js +23 -0
- package/lib/ReadWriteQueueHttp.js.map +1 -0
- package/lib/ReadWriteVolume.d.ts +40 -0
- package/lib/ReadWriteVolume.d.ts.map +1 -0
- package/lib/ReadWriteVolume.js +3 -0
- package/lib/ReadWriteVolume.js.map +1 -0
- package/lib/ReadWriteVolumeHttp.d.ts +12 -0
- package/lib/ReadWriteVolumeHttp.d.ts.map +1 -0
- package/lib/ReadWriteVolumeHttp.js +24 -0
- package/lib/ReadWriteVolumeHttp.js.map +1 -0
- package/lib/RuntimeOwner.d.ts +39 -0
- package/lib/RuntimeOwner.d.ts.map +1 -0
- package/lib/RuntimeOwner.js +85 -0
- package/lib/RuntimeOwner.js.map +1 -0
- package/lib/Sandbox.d.ts +215 -0
- package/lib/Sandbox.d.ts.map +1 -0
- package/lib/Sandbox.js +278 -0
- package/lib/Sandbox.js.map +1 -0
- package/lib/SandboxClient.d.ts +748 -0
- package/lib/SandboxClient.d.ts.map +1 -0
- package/lib/SandboxClient.js +710 -0
- package/lib/SandboxClient.js.map +1 -0
- package/lib/ScaleFunction.d.ts +54 -0
- package/lib/ScaleFunction.d.ts.map +1 -0
- package/lib/ScaleFunction.js +3 -0
- package/lib/ScaleFunction.js.map +1 -0
- package/lib/ScaleFunctionHttp.d.ts +21 -0
- package/lib/ScaleFunctionHttp.d.ts.map +1 -0
- package/lib/ScaleFunctionHttp.js +39 -0
- package/lib/ScaleFunctionHttp.js.map +1 -0
- package/lib/Secret.d.ts +170 -0
- package/lib/Secret.d.ts.map +1 -0
- package/lib/Secret.js +196 -0
- package/lib/Secret.js.map +1 -0
- package/lib/Server.d.ts +155 -0
- package/lib/Server.d.ts.map +1 -0
- package/lib/Server.js +184 -0
- package/lib/Server.js.map +1 -0
- package/lib/ServiceUser.d.ts +139 -0
- package/lib/ServiceUser.d.ts.map +1 -0
- package/lib/ServiceUser.js +210 -0
- package/lib/ServiceUser.js.map +1 -0
- package/lib/Volume.d.ts +170 -0
- package/lib/Volume.d.ts.map +1 -0
- package/lib/Volume.js +220 -0
- package/lib/Volume.js.map +1 -0
- package/lib/VolumeClient.d.ts +53 -0
- package/lib/VolumeClient.d.ts.map +1 -0
- package/lib/VolumeClient.js +22 -0
- package/lib/VolumeClient.js.map +1 -0
- package/lib/VolumeFiles.d.ts +94 -0
- package/lib/VolumeFiles.d.ts.map +1 -0
- package/lib/VolumeFiles.js +139 -0
- package/lib/VolumeFiles.js.map +1 -0
- package/lib/WebhookToken.d.ts +102 -0
- package/lib/WebhookToken.d.ts.map +1 -0
- package/lib/WebhookToken.js +176 -0
- package/lib/WebhookToken.js.map +1 -0
- package/lib/WorkspaceSettings.d.ts +70 -0
- package/lib/WorkspaceSettings.d.ts.map +1 -0
- package/lib/WorkspaceSettings.js +105 -0
- package/lib/WorkspaceSettings.js.map +1 -0
- package/lib/WriteApp.d.ts +38 -0
- package/lib/WriteApp.d.ts.map +1 -0
- package/lib/WriteApp.js +3 -0
- package/lib/WriteApp.js.map +1 -0
- package/lib/WriteAppHttp.d.ts +23 -0
- package/lib/WriteAppHttp.d.ts.map +1 -0
- package/lib/WriteAppHttp.js +36 -0
- package/lib/WriteAppHttp.js.map +1 -0
- package/lib/WriteDict.d.ts +39 -0
- package/lib/WriteDict.d.ts.map +1 -0
- package/lib/WriteDict.js +3 -0
- package/lib/WriteDict.js.map +1 -0
- package/lib/WriteDictHttp.d.ts +12 -0
- package/lib/WriteDictHttp.d.ts.map +1 -0
- package/lib/WriteDictHttp.js +23 -0
- package/lib/WriteDictHttp.js.map +1 -0
- package/lib/WriteQueue.d.ts +39 -0
- package/lib/WriteQueue.d.ts.map +1 -0
- package/lib/WriteQueue.js +3 -0
- package/lib/WriteQueue.js.map +1 -0
- package/lib/WriteQueueHttp.d.ts +12 -0
- package/lib/WriteQueueHttp.d.ts.map +1 -0
- package/lib/WriteQueueHttp.js +23 -0
- package/lib/WriteQueueHttp.js.map +1 -0
- package/lib/WriteSecret.d.ts +53 -0
- package/lib/WriteSecret.d.ts.map +1 -0
- package/lib/WriteSecret.js +3 -0
- package/lib/WriteSecret.js.map +1 -0
- package/lib/WriteSecretHttp.d.ts +23 -0
- package/lib/WriteSecretHttp.d.ts.map +1 -0
- package/lib/WriteSecretHttp.js +44 -0
- package/lib/WriteSecretHttp.js.map +1 -0
- package/lib/WriteVolume.d.ts +39 -0
- package/lib/WriteVolume.d.ts.map +1 -0
- package/lib/WriteVolume.js +3 -0
- package/lib/WriteVolume.js.map +1 -0
- package/lib/WriteVolumeHttp.d.ts +12 -0
- package/lib/WriteVolumeHttp.d.ts.map +1 -0
- package/lib/WriteVolumeHttp.js +24 -0
- package/lib/WriteVolumeHttp.js.map +1 -0
- package/lib/index.d.ts +80 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +78 -0
- package/lib/index.js.map +1 -0
- package/lib/internal/Declared.d.ts +29 -0
- package/lib/internal/Declared.d.ts.map +1 -0
- package/lib/internal/Declared.js +31 -0
- package/lib/internal/Declared.js.map +1 -0
- package/lib/internal/Deploy.d.ts +110 -0
- package/lib/internal/Deploy.d.ts.map +1 -0
- package/lib/internal/Deploy.js +230 -0
- package/lib/internal/Deploy.js.map +1 -0
- package/lib/internal/Entrypoint.d.ts +52 -0
- package/lib/internal/Entrypoint.d.ts.map +1 -0
- package/lib/internal/Entrypoint.js +193 -0
- package/lib/internal/Entrypoint.js.map +1 -0
- package/lib/internal/Rpc.d.ts +17 -0
- package/lib/internal/Rpc.d.ts.map +1 -0
- package/lib/internal/Rpc.js +49 -0
- package/lib/internal/Rpc.js.map +1 -0
- package/lib/internal/RpcAuth.d.ts +41 -0
- package/lib/internal/RpcAuth.d.ts.map +1 -0
- package/lib/internal/RpcAuth.js +100 -0
- package/lib/internal/RpcAuth.js.map +1 -0
- package/lib/internal/Runtime.d.ts +127 -0
- package/lib/internal/Runtime.d.ts.map +1 -0
- package/lib/internal/Runtime.js +246 -0
- package/lib/internal/Runtime.js.map +1 -0
- package/lib/internal/Tags.d.ts +19 -0
- package/lib/internal/Tags.d.ts.map +1 -0
- package/lib/internal/Tags.js +33 -0
- package/lib/internal/Tags.js.map +1 -0
- package/lib/internal/TcpConnect.d.ts +12 -0
- package/lib/internal/TcpConnect.d.ts.map +1 -0
- package/lib/internal/TcpConnect.js +46 -0
- package/lib/internal/TcpConnect.js.map +1 -0
- package/lib/internal/Transport.d.ts +13 -0
- package/lib/internal/Transport.d.ts.map +1 -0
- package/lib/internal/Transport.js +16 -0
- package/lib/internal/Transport.js.map +1 -0
- package/lib/internal.d.ts +71 -0
- package/lib/internal.d.ts.map +1 -0
- package/lib/internal.js +102 -0
- package/lib/internal.js.map +1 -0
- package/package.json +59 -3
- package/src/App.ts +262 -0
- package/src/AuthProvider.ts +295 -0
- package/src/BindingHttp.ts +112 -0
- package/src/Blob.ts +71 -0
- package/src/Bootstrap.ts +52 -0
- package/src/Cbor.ts +158 -0
- package/src/ConnectSandbox.ts +99 -0
- package/src/Container.ts +121 -0
- package/src/Contributions.ts +9 -0
- package/src/CreateDict.ts +95 -0
- package/src/CreateDictHttp.ts +91 -0
- package/src/CreateImage.ts +105 -0
- package/src/CreateImageHttp.ts +117 -0
- package/src/CreateQueue.ts +95 -0
- package/src/CreateQueueHttp.ts +91 -0
- package/src/CreateSandbox.ts +228 -0
- package/src/CreateSandboxHttp.ts +160 -0
- package/src/CreateSecret.ts +109 -0
- package/src/CreateSecretHttp.ts +83 -0
- package/src/CreateVolume.ts +96 -0
- package/src/CreateVolumeHttp.ts +93 -0
- package/src/Credentials.ts +74 -0
- package/src/Dict.ts +245 -0
- package/src/DictClient.ts +166 -0
- package/src/Domain.ts +147 -0
- package/src/Endpoint.ts +406 -0
- package/src/Environment.ts +373 -0
- package/src/FetchServer.ts +126 -0
- package/src/FetchServerHttp.ts +110 -0
- package/src/Function.ts +397 -0
- package/src/FunctionAutoscaler.ts +210 -0
- package/src/FunctionTarget.ts +181 -0
- package/src/Image.ts +281 -0
- package/src/ImageBuild.ts +228 -0
- package/src/ImagePlan.ts +78 -0
- package/src/InferEnv.ts +27 -0
- package/src/InvokeFunction.ts +211 -0
- package/src/InvokeFunctionHttp.ts +316 -0
- package/src/ModalBindings.ts +310 -0
- package/src/MountBucket.ts +137 -0
- package/src/MountVolume.ts +113 -0
- package/src/Mounts.ts +230 -0
- package/src/PersistentSandbox.ts +142 -0
- package/src/Providers.ts +100 -0
- package/src/Proxy.ts +191 -0
- package/src/Queue.ts +258 -0
- package/src/QueueClient.ts +149 -0
- package/src/ReadApp.ts +101 -0
- package/src/ReadAppHttp.ts +142 -0
- package/src/ReadDict.ts +44 -0
- package/src/ReadDictHttp.ts +27 -0
- package/src/ReadFunction.ts +107 -0
- package/src/ReadFunctionHttp.ts +91 -0
- package/src/ReadQueue.ts +44 -0
- package/src/ReadQueueHttp.ts +27 -0
- package/src/ReadServer.ts +98 -0
- package/src/ReadServerHttp.ts +101 -0
- package/src/ReadVolume.ts +45 -0
- package/src/ReadVolumeHttp.ts +28 -0
- package/src/ReadWriteDict.ts +44 -0
- package/src/ReadWriteDictHttp.ts +27 -0
- package/src/ReadWriteQueue.ts +45 -0
- package/src/ReadWriteQueueHttp.ts +27 -0
- package/src/ReadWriteVolume.ts +45 -0
- package/src/ReadWriteVolumeHttp.ts +28 -0
- package/src/RuntimeOwner.ts +111 -0
- package/src/Sandbox.ts +402 -0
- package/src/SandboxClient.ts +1404 -0
- package/src/ScaleFunction.ts +70 -0
- package/src/ScaleFunctionHttp.ts +54 -0
- package/src/Secret.ts +296 -0
- package/src/Server.ts +285 -0
- package/src/ServiceUser.ts +295 -0
- package/src/Volume.ts +320 -0
- package/src/VolumeClient.ts +108 -0
- package/src/VolumeFiles.ts +194 -0
- package/src/WebhookToken.ts +230 -0
- package/src/WorkspaceSettings.ts +160 -0
- package/src/WriteApp.ts +43 -0
- package/src/WriteAppHttp.ts +51 -0
- package/src/WriteDict.ts +44 -0
- package/src/WriteDictHttp.ts +27 -0
- package/src/WriteQueue.ts +44 -0
- package/src/WriteQueueHttp.ts +27 -0
- package/src/WriteSecret.ts +60 -0
- package/src/WriteSecretHttp.ts +56 -0
- package/src/WriteVolume.ts +44 -0
- package/src/WriteVolumeHttp.ts +28 -0
- package/src/globals.d.ts +2 -0
- package/src/index.ts +85 -0
- package/src/internal/Declared.ts +80 -0
- package/src/internal/Deploy.ts +309 -0
- package/src/internal/Entrypoint.ts +198 -0
- package/src/internal/Rpc.ts +59 -0
- package/src/internal/RpcAuth.ts +132 -0
- package/src/internal/Runtime.ts +386 -0
- package/src/internal/Tags.ts +44 -0
- package/src/internal/TcpConnect.ts +78 -0
- package/src/internal/Transport.ts +25 -0
- package/src/internal.ts +147 -0
|
@@ -0,0 +1,710 @@
|
|
|
1
|
+
import * as persistent from "@distilled.cloud/modal/persistent";
|
|
2
|
+
import * as sandbox from "@distilled.cloud/modal/sandbox";
|
|
3
|
+
import * as router from "@distilled.cloud/modal/task_command_router";
|
|
4
|
+
import * as Sandbox from "alchemy/Sandbox";
|
|
5
|
+
import * as SecureRandom from "effect/crypto/SecureRandom";
|
|
6
|
+
import * as Data from "effect/Data";
|
|
7
|
+
import * as DateTime from "effect/DateTime";
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import * as HttpClient from "effect/http/HttpClient";
|
|
10
|
+
import * as HttpClientRequest from "effect/http/HttpClientRequest";
|
|
11
|
+
import * as Schedule from "effect/Schedule";
|
|
12
|
+
import * as Stream from "effect/Stream";
|
|
13
|
+
import { buildImage, gpuConfig, ImageBuildOps } from "./ImageBuild.js";
|
|
14
|
+
import { environmentOf, operations, seconds } from "./internal.js";
|
|
15
|
+
import { connectTcp } from "./internal/TcpConnect.js";
|
|
16
|
+
import { streamRouter, withRouter } from "./ModalBindings.js";
|
|
17
|
+
import { modalMountsOf } from "./Mounts.js";
|
|
18
|
+
/** A sandbox ended (or never became ready) before the call could finish. */
|
|
19
|
+
export class SandboxNotRunning extends Data.TaggedError("Modal.SandboxNotRunning") {
|
|
20
|
+
}
|
|
21
|
+
/** A Modal call returned without the field the client needs. */
|
|
22
|
+
export class SandboxUnexpectedResponse extends Data.TaggedError("Modal.SandboxUnexpectedResponse") {
|
|
23
|
+
}
|
|
24
|
+
/** A filesystem operation inside the sandbox failed (missing path, permissions). */
|
|
25
|
+
export class SandboxFilesystemError extends Data.TaggedError("Modal.SandboxFilesystemError") {
|
|
26
|
+
}
|
|
27
|
+
/** Modal's task command router has no call to resize a running PTY. */
|
|
28
|
+
export class SandboxPtyResizeUnsupported extends Data.TaggedError("Modal.SandboxPtyResizeUnsupported") {
|
|
29
|
+
}
|
|
30
|
+
/** The text of a command's output stream, from its router read chunks. */
|
|
31
|
+
const streamText = (chunks) => Buffer.concat(chunks.map((chunk) => Buffer.from(chunk.data ?? "", "base64"))).toString("utf8");
|
|
32
|
+
const decodeBase64 = (data) => Effect.sync(() => new Uint8Array(Buffer.from(data, "base64")));
|
|
33
|
+
const encodeBase64 = (data) => Effect.sync(() => typeof data === "string"
|
|
34
|
+
? Buffer.from(data, "utf8").toString("base64")
|
|
35
|
+
: Buffer.from(data).toString("base64"));
|
|
36
|
+
const tunnelTypeOf = (h2) => h2 ? "TUNNEL_TYPE_H2" : undefined;
|
|
37
|
+
/** Modal's `Sandbox` definition for {@link SandboxCreateOptions}. */
|
|
38
|
+
const definitionOf = (imageId, options, mounts) => ({
|
|
39
|
+
imageId,
|
|
40
|
+
entrypointArgs: options.command ? [...options.command] : ["sleep", "infinity"],
|
|
41
|
+
workdir: options.workdir,
|
|
42
|
+
environmentVariables: options.env,
|
|
43
|
+
secretIds: options.secrets?.map((s) => s.secretId),
|
|
44
|
+
volumeMounts: mounts.volumeMounts,
|
|
45
|
+
cloudBucketMounts: mounts.cloudBucketMounts,
|
|
46
|
+
resources: {
|
|
47
|
+
milliCpu: options.cpu !== undefined ? Math.round(options.cpu * 1000) : undefined,
|
|
48
|
+
memoryMb: options.memory,
|
|
49
|
+
gpuConfig: gpuConfig(options.gpu),
|
|
50
|
+
ephemeralDiskMb: options.ephemeralDisk,
|
|
51
|
+
},
|
|
52
|
+
timeoutSecs: seconds(options.timeout),
|
|
53
|
+
idleTimeoutSecs: seconds(options.idleTimeout),
|
|
54
|
+
name: options.name,
|
|
55
|
+
schedulerPlacement: options.regions ? { regions: [...options.regions] } : undefined,
|
|
56
|
+
blockNetwork: options.blockNetwork,
|
|
57
|
+
networkAccess: networkAccessOf(options),
|
|
58
|
+
inboundCidrAllowlist: options.inboundCidrAllowlist
|
|
59
|
+
? [...options.inboundCidrAllowlist]
|
|
60
|
+
: undefined,
|
|
61
|
+
outboundPolicy: options.outboundPolicy ? outboundPolicyOf(options.outboundPolicy) : undefined,
|
|
62
|
+
proxyId: options.proxy?.proxyId,
|
|
63
|
+
includeOidcIdentityToken: options.includeOidcIdentityToken,
|
|
64
|
+
includeX509Svid: options.includeX509Svid,
|
|
65
|
+
openPorts: {
|
|
66
|
+
ports: [
|
|
67
|
+
...(options.encryptedPorts ?? []).map((port) => ({ port })),
|
|
68
|
+
...(options.unencryptedPorts ?? []).map((port) => ({ port, unencrypted: true })),
|
|
69
|
+
...(options.h2Ports ?? []).map((port) => ({ port, tunnelType: tunnelTypeOf(true) })),
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
enableSnapshot: options.enableSnapshot,
|
|
73
|
+
customDomain: options.customDomain,
|
|
74
|
+
});
|
|
75
|
+
const networkAccessOf = (options) => options.blockNetwork
|
|
76
|
+
? { networkAccessType: "BLOCKED" }
|
|
77
|
+
: options.cidrAllowlist !== undefined || options.allowedDomains !== undefined
|
|
78
|
+
? {
|
|
79
|
+
networkAccessType: "ALLOWLIST",
|
|
80
|
+
allowedCidrs: options.cidrAllowlist ? [...options.cidrAllowlist] : [],
|
|
81
|
+
allowedDomains: options.allowedDomains ? [...options.allowedDomains] : [],
|
|
82
|
+
}
|
|
83
|
+
: undefined;
|
|
84
|
+
/**
|
|
85
|
+
* The policy for a sandbox that is already running. Modal's task router
|
|
86
|
+
* accepts only an allow-list here: an empty one blocks everything, and
|
|
87
|
+
* `0.0.0.0/0` opens the network.
|
|
88
|
+
*/
|
|
89
|
+
const runningNetworkAccessOf = (access) => {
|
|
90
|
+
const open = access.cidrAllowlist === undefined && access.allowedDomains === undefined;
|
|
91
|
+
return {
|
|
92
|
+
networkAccessType: "ALLOWLIST",
|
|
93
|
+
allowedCidrs: access.blockNetwork
|
|
94
|
+
? []
|
|
95
|
+
: open
|
|
96
|
+
? ["0.0.0.0/0"]
|
|
97
|
+
: [...(access.cidrAllowlist ?? [])],
|
|
98
|
+
allowedDomains: access.blockNetwork ? [] : [...(access.allowedDomains ?? [])],
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
const portsOf = (ports) => ports?.map((port) => (typeof port === "number" ? { start: port, end: port } : port));
|
|
102
|
+
const transportOf = (transport) => transport === undefined ? undefined : `TRANSPORT_${transport.toUpperCase()}`;
|
|
103
|
+
const redirectOf = (redirect) => redirect === undefined
|
|
104
|
+
? undefined
|
|
105
|
+
: redirect === "block"
|
|
106
|
+
? { block: {} }
|
|
107
|
+
: "proxy" in redirect
|
|
108
|
+
? { viaProxy: { proxyId: redirect.proxy.proxyId } }
|
|
109
|
+
: { viaSidecar: { sidecarName: redirect.sidecar } };
|
|
110
|
+
const outboundPolicyOf = (policy) => ({
|
|
111
|
+
tlsDecryption: {
|
|
112
|
+
allowed: policy.tlsDecryption ?? policy.routes.some((route) => "https" in route),
|
|
113
|
+
},
|
|
114
|
+
routes: policy.routes.map((route) => {
|
|
115
|
+
if ("ip" in route) {
|
|
116
|
+
return {
|
|
117
|
+
ip: {
|
|
118
|
+
cidrs: [...route.ip.cidrs],
|
|
119
|
+
ports: portsOf(route.ip.ports),
|
|
120
|
+
transport: transportOf(route.ip.transport),
|
|
121
|
+
redirect: redirectOf(route.ip.redirect),
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if ("tls" in route) {
|
|
126
|
+
return {
|
|
127
|
+
tls: {
|
|
128
|
+
domains: [...route.tls.domains],
|
|
129
|
+
ports: portsOf(route.tls.ports),
|
|
130
|
+
redirect: redirectOf(route.tls.redirect),
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if ("https" in route) {
|
|
135
|
+
return {
|
|
136
|
+
https: {
|
|
137
|
+
domains: [...route.https.domains],
|
|
138
|
+
ports: portsOf(route.https.ports),
|
|
139
|
+
headerReplacements: route.https.headerReplacements?.map((r) => ({
|
|
140
|
+
secretId: r.secret?.secretId,
|
|
141
|
+
headers: r.headers,
|
|
142
|
+
})),
|
|
143
|
+
redirect: redirectOf(route.https.redirect),
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
return { any: { redirect: redirectOf(route.any.redirect) } };
|
|
148
|
+
}),
|
|
149
|
+
});
|
|
150
|
+
/**
|
|
151
|
+
* The operations sandbox clients call, resolved once by
|
|
152
|
+
* `ModalBindings.withCredentials` (or at deploy, with the deployer's).
|
|
153
|
+
*/
|
|
154
|
+
export const SandboxOps = operations({
|
|
155
|
+
create: sandbox.sandboxCreateV2,
|
|
156
|
+
getFromName: sandbox.sandboxGetFromNameV2,
|
|
157
|
+
list: sandbox.sandboxListV2,
|
|
158
|
+
restore: sandbox.sandboxRestoreV2,
|
|
159
|
+
getTaskId: sandbox.sandboxGetTaskIdV2,
|
|
160
|
+
getCommandRouterAccess: sandbox.sandboxGetCommandRouterAccess,
|
|
161
|
+
getTunnels: sandbox.sandboxGetTunnelsV2,
|
|
162
|
+
createConnectToken: sandbox.sandboxCreateConnectTokenV2,
|
|
163
|
+
setOutboundPolicy: sandbox.sandboxSetOutboundPolicyV2,
|
|
164
|
+
setTags: sandbox.sandboxTagsSetV2,
|
|
165
|
+
getTags: sandbox.sandboxTagsGetV2,
|
|
166
|
+
setName: sandbox.sandboxSetName,
|
|
167
|
+
getResourceUsage: sandbox.sandboxGetResourceUsage,
|
|
168
|
+
wait: sandbox.sandboxWaitV2,
|
|
169
|
+
terminate: sandbox.sandboxTerminateV2,
|
|
170
|
+
usage: sandbox.sandboxGetTimeRangeStats,
|
|
171
|
+
createPersistent: persistent.createPersistentSandbox,
|
|
172
|
+
getPersistent: persistent.getPersistentSandbox,
|
|
173
|
+
resumePersistent: persistent.resumePersistentSandbox,
|
|
174
|
+
terminatePersistent: persistent.terminatePersistentSandbox,
|
|
175
|
+
images: ImageBuildOps,
|
|
176
|
+
http: HttpClient.HttpClient,
|
|
177
|
+
});
|
|
178
|
+
/** Task command router operations, resolved per sandbox with its router access. */
|
|
179
|
+
const routerOps = {
|
|
180
|
+
execStart: withRouter(router.taskExecStart),
|
|
181
|
+
execStdinWrite: withRouter(router.taskExecStdinWrite),
|
|
182
|
+
execStdioRead: withRouter(router.taskExecStdioRead),
|
|
183
|
+
execWait: withRouter(router.taskExecWait),
|
|
184
|
+
// A running command's output, each chunk as the router sends it; the
|
|
185
|
+
// stream ends when the command closes the descriptor.
|
|
186
|
+
execStdioFollow: streamRouter(router.taskExecStdioRead),
|
|
187
|
+
snapshotFilesystem: withRouter(router.taskSnapshotFilesystem),
|
|
188
|
+
snapshotMemory: withRouter(router.taskSnapshotMemory),
|
|
189
|
+
snapshotDirectory: withRouter(router.taskSnapshotDirectory),
|
|
190
|
+
mountDirectory: withRouter(router.taskMountDirectory),
|
|
191
|
+
setNetworkAccess: withRouter(router.taskSetNetworkAccess),
|
|
192
|
+
// The sandbox's own program's output (V2 sandboxes serve it here, not
|
|
193
|
+
// through the control plane's sandboxGetLogs).
|
|
194
|
+
mainStdio: streamRouter(router.sandboxStdioReadV2),
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* The image to boot: a `Modal.Image`'s id, or a registry ref built (and
|
|
198
|
+
* cached by Modal) into an image in the target app.
|
|
199
|
+
*/
|
|
200
|
+
export const resolveSandboxImage = Effect.fn(function* (ops, target, image) {
|
|
201
|
+
if (image !== undefined && typeof image !== "string")
|
|
202
|
+
return image.imageId;
|
|
203
|
+
if (image === undefined && target.imageId !== undefined)
|
|
204
|
+
return target.imageId;
|
|
205
|
+
const spec = { dockerTag: image ?? "debian:bookworm-slim", commands: [] };
|
|
206
|
+
return yield* buildImage(ops.images, target.appId, spec);
|
|
207
|
+
});
|
|
208
|
+
/** The handle for an existing sandbox id. */
|
|
209
|
+
export const sandboxHandle = (ops, sandboxId, target) => {
|
|
210
|
+
let cachedTaskId;
|
|
211
|
+
const taskId = Effect.gen(function* () {
|
|
212
|
+
if (cachedTaskId !== undefined)
|
|
213
|
+
return cachedTaskId;
|
|
214
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
215
|
+
const response = yield* ops.getTaskId({
|
|
216
|
+
sandboxId,
|
|
217
|
+
timeout: 55,
|
|
218
|
+
waitUntilReady: true,
|
|
219
|
+
});
|
|
220
|
+
if (response.taskId) {
|
|
221
|
+
cachedTaskId = response.taskId;
|
|
222
|
+
return response.taskId;
|
|
223
|
+
}
|
|
224
|
+
if (response.taskResult?.status &&
|
|
225
|
+
response.taskResult.status !== "GENERIC_STATUS_UNSPECIFIED") {
|
|
226
|
+
return yield* new SandboxNotRunning({
|
|
227
|
+
sandboxId,
|
|
228
|
+
message: `Sandbox ${sandboxId} finished with ${response.taskResult.status}`,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return yield* new SandboxNotRunning({
|
|
233
|
+
sandboxId,
|
|
234
|
+
message: `Sandbox ${sandboxId} wasn't scheduled within 9 minutes`,
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
const viaRouter = (resolve, f) => Effect.gen(function* () {
|
|
238
|
+
const id = yield* taskId;
|
|
239
|
+
const access = yield* ops.getCommandRouterAccess({ taskId: id });
|
|
240
|
+
if (!access.url || !access.jwt) {
|
|
241
|
+
return yield* new SandboxUnexpectedResponse({
|
|
242
|
+
message: `Modal returned no command router for sandbox ${sandboxId}`,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
const op = yield* resolve({ url: access.url, jwt: access.jwt });
|
|
246
|
+
return yield* f(op, id);
|
|
247
|
+
});
|
|
248
|
+
/**
|
|
249
|
+
* Run a filesystem command with `sh` (every image Modal boots has one) and
|
|
250
|
+
* fail with {@link SandboxFilesystemError} on a non-zero exit.
|
|
251
|
+
*/
|
|
252
|
+
const fsExec = (path, script, stdin) => Effect.flatMap(exec(["sh", "-c", script, "sh", path], stdin === undefined ? {} : { stdin }), (result) => result.exitCode === 0
|
|
253
|
+
? Effect.succeed(result.stdout)
|
|
254
|
+
: Effect.fail(new SandboxFilesystemError({
|
|
255
|
+
path,
|
|
256
|
+
message: result.stderr.trim() || `exit code ${result.exitCode}`,
|
|
257
|
+
})));
|
|
258
|
+
const exec = Effect.fn(function* (command, options = {}) {
|
|
259
|
+
// V2 sandboxes run commands through the task command router: start the
|
|
260
|
+
// command under an id we choose, then read its output streams while
|
|
261
|
+
// waiting for it to exit.
|
|
262
|
+
const id = yield* taskId;
|
|
263
|
+
const access = yield* ops.getCommandRouterAccess({ taskId: id });
|
|
264
|
+
if (!access.url || !access.jwt) {
|
|
265
|
+
return yield* new SandboxUnexpectedResponse({
|
|
266
|
+
message: `Modal returned no command router for sandbox ${sandboxId}`,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
const at = { url: access.url, jwt: access.jwt };
|
|
270
|
+
const start = yield* routerOps.execStart(at);
|
|
271
|
+
const stdinWrite = yield* routerOps.execStdinWrite(at);
|
|
272
|
+
const stdioRead = yield* routerOps.execStdioRead(at);
|
|
273
|
+
const wait = yield* routerOps.execWait(at);
|
|
274
|
+
const execId = yield* Effect.sync(() => SecureRandom.uuidV4Unsafe());
|
|
275
|
+
yield* start({
|
|
276
|
+
taskId: id,
|
|
277
|
+
execId,
|
|
278
|
+
commandArgs: typeof command === "string" ? ["sh", "-c", command] : [...command],
|
|
279
|
+
workdir: options.cwd,
|
|
280
|
+
timeoutSecs: seconds(options.timeout),
|
|
281
|
+
secretIds: options.secrets?.map((s) => s.secretId),
|
|
282
|
+
env: options.env,
|
|
283
|
+
stdoutConfig: "TASK_EXEC_STDOUT_CONFIG_PIPE",
|
|
284
|
+
stderrConfig: "TASK_EXEC_STDERR_CONFIG_PIPE",
|
|
285
|
+
});
|
|
286
|
+
if (options.stdin !== undefined) {
|
|
287
|
+
yield* stdinWrite({
|
|
288
|
+
taskId: id,
|
|
289
|
+
execId,
|
|
290
|
+
offset: "0",
|
|
291
|
+
data: yield* encodeBase64(options.stdin),
|
|
292
|
+
eof: true,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
const read = (fileDescriptor) => stdioRead({ taskId: id, execId, offset: "0", fileDescriptor }).pipe(Effect.map(({ items }) => streamText(items)));
|
|
296
|
+
const [stdout, stderr, exit] = yield* Effect.all([
|
|
297
|
+
read("TASK_EXEC_STDIO_FILE_DESCRIPTOR_STDOUT"),
|
|
298
|
+
read("TASK_EXEC_STDIO_FILE_DESCRIPTOR_STDERR"),
|
|
299
|
+
wait({ taskId: id, execId }),
|
|
300
|
+
], { concurrency: "unbounded" });
|
|
301
|
+
return {
|
|
302
|
+
exitCode: exit.code ?? (exit.signal !== undefined ? 128 + exit.signal : -1),
|
|
303
|
+
stdout,
|
|
304
|
+
stderr,
|
|
305
|
+
};
|
|
306
|
+
});
|
|
307
|
+
/** The task and its router access, for the router calls of one command. */
|
|
308
|
+
const routerAccess = Effect.gen(function* () {
|
|
309
|
+
const id = yield* taskId;
|
|
310
|
+
const access = yield* ops.getCommandRouterAccess({ taskId: id });
|
|
311
|
+
if (!access.url || !access.jwt) {
|
|
312
|
+
return yield* new SandboxUnexpectedResponse({
|
|
313
|
+
message: `Modal returned no command router for sandbox ${sandboxId}`,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
return { taskId: id, at: { url: access.url, jwt: access.jwt } };
|
|
317
|
+
});
|
|
318
|
+
/**
|
|
319
|
+
* Start a command (on a PTY with `pty`) and return how to follow it: a
|
|
320
|
+
* stream per output, stdin writes from a running offset, and its exit.
|
|
321
|
+
*/
|
|
322
|
+
const startExec = Effect.fn(function* (commandArgs, options, pty) {
|
|
323
|
+
const { taskId: id, at } = yield* routerAccess;
|
|
324
|
+
const begin = yield* routerOps.execStart(at);
|
|
325
|
+
const stdinWrite = yield* routerOps.execStdinWrite(at);
|
|
326
|
+
const follow = yield* routerOps.execStdioFollow(at);
|
|
327
|
+
const wait = yield* routerOps.execWait(at);
|
|
328
|
+
const execId = yield* Effect.sync(() => SecureRandom.uuidV4Unsafe());
|
|
329
|
+
yield* begin({
|
|
330
|
+
taskId: id,
|
|
331
|
+
execId,
|
|
332
|
+
commandArgs: [...commandArgs],
|
|
333
|
+
workdir: options.cwd,
|
|
334
|
+
timeoutSecs: seconds(options.timeout),
|
|
335
|
+
secretIds: options.secrets?.map((s) => s.secretId),
|
|
336
|
+
env: options.env,
|
|
337
|
+
stdoutConfig: "TASK_EXEC_STDOUT_CONFIG_PIPE",
|
|
338
|
+
stderrConfig: pty ? undefined : "TASK_EXEC_STDERR_CONFIG_PIPE",
|
|
339
|
+
ptyInfo: pty,
|
|
340
|
+
});
|
|
341
|
+
let stdinOffset = 0;
|
|
342
|
+
const write = (data, eof = false) => Effect.gen(function* () {
|
|
343
|
+
const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
|
|
344
|
+
const offset = stdinOffset;
|
|
345
|
+
stdinOffset += bytes.length;
|
|
346
|
+
yield* stdinWrite({
|
|
347
|
+
taskId: id,
|
|
348
|
+
execId,
|
|
349
|
+
offset: String(offset),
|
|
350
|
+
data: yield* encodeBase64(bytes),
|
|
351
|
+
eof,
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
/** One output of the command, each chunk as it arrives. */
|
|
355
|
+
const output = (fileDescriptor) => follow({ taskId: id, execId, offset: "0", fileDescriptor }).pipe(Stream.map((item) => new Uint8Array(Buffer.from(item.data, "base64"))), Stream.filter((bytes) => bytes.length > 0));
|
|
356
|
+
if (options.stdin !== undefined)
|
|
357
|
+
yield* write(options.stdin, true);
|
|
358
|
+
return {
|
|
359
|
+
execId,
|
|
360
|
+
write,
|
|
361
|
+
output,
|
|
362
|
+
wait: Effect.map(wait({ taskId: id, execId }), (exit) => ({
|
|
363
|
+
exitCode: exit.code ?? (exit.signal !== undefined ? 128 + exit.signal : -1),
|
|
364
|
+
})),
|
|
365
|
+
};
|
|
366
|
+
});
|
|
367
|
+
const argvOf = (command) => typeof command === "string" ? ["sh", "-c", command] : command;
|
|
368
|
+
const start = (command, options = {}) => Effect.gen(function* () {
|
|
369
|
+
// The router has no signal call: the command records its pid, and
|
|
370
|
+
// `kill` signals it with a second command.
|
|
371
|
+
const pidFile = `/tmp/.alchemy-exec-${yield* Effect.sync(() => SecureRandom.uuidV4Unsafe())}.pid`;
|
|
372
|
+
const running = yield* startExec(["sh", "-c", 'echo $$ > "$0"; exec "$@"', pidFile, ...argvOf(command)], options);
|
|
373
|
+
return {
|
|
374
|
+
id: running.execId,
|
|
375
|
+
output: Stream.merge(Stream.map(running.output("TASK_EXEC_STDIO_FILE_DESCRIPTOR_STDOUT"), (data) => ({
|
|
376
|
+
fd: "stdout",
|
|
377
|
+
data,
|
|
378
|
+
})), Stream.map(running.output("TASK_EXEC_STDIO_FILE_DESCRIPTOR_STDERR"), (data) => ({
|
|
379
|
+
fd: "stderr",
|
|
380
|
+
data,
|
|
381
|
+
}))),
|
|
382
|
+
write: (data) => running.write(data),
|
|
383
|
+
kill: (signal = "SIGTERM") => Effect.asVoid(exec(["sh", "-c", `kill -s ${signal.slice(3)} "$(cat "$0")"`, pidFile])),
|
|
384
|
+
wait: running.wait,
|
|
385
|
+
};
|
|
386
|
+
});
|
|
387
|
+
const pty = {
|
|
388
|
+
open: (options) => Effect.gen(function* () {
|
|
389
|
+
const running = yield* startExec(options.command
|
|
390
|
+
? ["sh", "-c", options.command]
|
|
391
|
+
: ["sh", "-c", "exec bash -l 2>/dev/null || exec sh -l"], { cwd: options.cwd, env: options.env, secrets: options.secrets }, {
|
|
392
|
+
enabled: true,
|
|
393
|
+
winszRows: options.rows,
|
|
394
|
+
winszCols: options.cols,
|
|
395
|
+
envTerm: "xterm-256color",
|
|
396
|
+
ptyType: "PTY_TYPE_SHELL",
|
|
397
|
+
noTerminateOnIdleStdin: true,
|
|
398
|
+
});
|
|
399
|
+
return {
|
|
400
|
+
id: running.execId,
|
|
401
|
+
output: running.output("TASK_EXEC_STDIO_FILE_DESCRIPTOR_STDOUT"),
|
|
402
|
+
write: (data) => running.write(data),
|
|
403
|
+
resize: () => Effect.fail(new SandboxPtyResizeUnsupported({
|
|
404
|
+
message: "Modal's task command router can't resize a running PTY",
|
|
405
|
+
})),
|
|
406
|
+
};
|
|
407
|
+
}),
|
|
408
|
+
};
|
|
409
|
+
const read = Effect.fn(function* (path) {
|
|
410
|
+
// base64 keeps binary content intact through the text output stream.
|
|
411
|
+
const encoded = yield* fsExec(path, 'base64 < "$1" | tr -d "\\n"');
|
|
412
|
+
return yield* decodeBase64(encoded);
|
|
413
|
+
});
|
|
414
|
+
const typeOf = (letter) => letter === "d" ? "directory" : letter === "l" ? "symlink" : letter === "f" ? "file" : "other";
|
|
415
|
+
const files = {
|
|
416
|
+
read,
|
|
417
|
+
readText: (path) => read(path).pipe(Effect.map((bytes) => new TextDecoder().decode(bytes))),
|
|
418
|
+
write: Effect.fn(function* (path, data) {
|
|
419
|
+
const encoded = yield* encodeBase64(data);
|
|
420
|
+
yield* fsExec(path, 'mkdir -p "$(dirname "$1")" && base64 -d > "$1"', encoded);
|
|
421
|
+
}),
|
|
422
|
+
list: Effect.fn(function* (path) {
|
|
423
|
+
const output = yield* fsExec(path, 'cd "$1" && for f in * .[!.]* ..?*; do [ -e "$f" ] || [ -L "$f" ] || continue; if [ -L "$f" ]; then echo "l $f"; elif [ -d "$f" ]; then echo "d $f"; elif [ -f "$f" ]; then echo "f $f"; else echo "o $f"; fi; done');
|
|
424
|
+
return output
|
|
425
|
+
.split("\n")
|
|
426
|
+
.filter((line) => line.length > 2)
|
|
427
|
+
.map((line) => ({
|
|
428
|
+
path: `${path.replace(/\/$/, "")}/${line.slice(2)}`,
|
|
429
|
+
type: typeOf(line[0]),
|
|
430
|
+
}));
|
|
431
|
+
}),
|
|
432
|
+
stat: Effect.fn(function* (path) {
|
|
433
|
+
// `%F` is GNU stat's type name; busybox prints the same names.
|
|
434
|
+
const output = yield* fsExec(path, 'stat -c "%F|%s|%Y" "$1"');
|
|
435
|
+
const [kind = "", size = "0", mtime = "0"] = output.trim().split("|");
|
|
436
|
+
return {
|
|
437
|
+
path,
|
|
438
|
+
type: kind.includes("directory")
|
|
439
|
+
? "directory"
|
|
440
|
+
: kind.includes("symbolic link")
|
|
441
|
+
? "symlink"
|
|
442
|
+
: kind.includes("regular")
|
|
443
|
+
? "file"
|
|
444
|
+
: "other",
|
|
445
|
+
size: Number(size),
|
|
446
|
+
modifiedAt: DateTime.makeUnsafe(Number(mtime) * 1000),
|
|
447
|
+
};
|
|
448
|
+
}),
|
|
449
|
+
remove: Effect.fn(function* (path, options = {}) {
|
|
450
|
+
yield* fsExec(path, options.recursive ? 'rm -r "$1"' : 'rm "$1"');
|
|
451
|
+
}),
|
|
452
|
+
makeDir: Effect.fn(function* (path) {
|
|
453
|
+
yield* fsExec(path, 'mkdir -p "$1"');
|
|
454
|
+
}),
|
|
455
|
+
};
|
|
456
|
+
const tunnelsOf = Effect.fn(function* (timeout) {
|
|
457
|
+
const { tunnels } = yield* ops.getTunnels({
|
|
458
|
+
sandboxId,
|
|
459
|
+
timeout: seconds(timeout) ?? 50,
|
|
460
|
+
});
|
|
461
|
+
const out = {};
|
|
462
|
+
for (const tunnel of tunnels ?? []) {
|
|
463
|
+
if (tunnel.containerPort === undefined)
|
|
464
|
+
continue;
|
|
465
|
+
const encrypted = tunnel.host !== undefined && tunnel.host !== "";
|
|
466
|
+
const host = (encrypted ? tunnel.host : tunnel.unencryptedHost) ?? "";
|
|
467
|
+
const port = (encrypted ? tunnel.port : tunnel.unencryptedPort) ?? 443;
|
|
468
|
+
out[tunnel.containerPort] = {
|
|
469
|
+
host,
|
|
470
|
+
port,
|
|
471
|
+
url: encrypted
|
|
472
|
+
? `https://${host}${port === 443 ? "" : `:${port}`}`
|
|
473
|
+
: `tcp://${host}:${port}`,
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
return out;
|
|
477
|
+
});
|
|
478
|
+
const getTcpPort = Effect.fn(function* (port = target.program?.port) {
|
|
479
|
+
if (port === undefined) {
|
|
480
|
+
return yield* new SandboxUnexpectedResponse({
|
|
481
|
+
message: "getTcpPort needs a port: create the sandbox from a Modal.Sandbox, or pass one",
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
const tunnel = (yield* tunnelsOf(50))[port];
|
|
485
|
+
if (!tunnel) {
|
|
486
|
+
return yield* new SandboxUnexpectedResponse({
|
|
487
|
+
message: `Port ${port} of sandbox ${sandboxId} has no tunnel; open it with encryptedPorts`,
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
const tls = tunnel.url.startsWith("https:");
|
|
491
|
+
// An unencrypted tunnel carries plain TCP, so HTTP to it is cleartext.
|
|
492
|
+
const origin = tls ? tunnel.url : `http://${tunnel.host}:${tunnel.port}`;
|
|
493
|
+
const sandboxPort = {
|
|
494
|
+
...tunnel,
|
|
495
|
+
// The user's own program, reached through its tunnel (allowed raw HTTP).
|
|
496
|
+
fetch: Sandbox.portFetch((request) => {
|
|
497
|
+
const url = new URL(request.url, "http://sandbox");
|
|
498
|
+
// The tunnel routes by host, so a proxied request's own `host` goes.
|
|
499
|
+
return ops.http.execute(HttpClientRequest.setUrl(HttpClientRequest.removeHeader(request, "host"), `${origin}${url.pathname}${url.search}`));
|
|
500
|
+
}),
|
|
501
|
+
connect: () => connectTcp({ host: tunnel.host, port: tunnel.port, tls }),
|
|
502
|
+
};
|
|
503
|
+
return sandboxPort;
|
|
504
|
+
});
|
|
505
|
+
const handle = {
|
|
506
|
+
sandboxId,
|
|
507
|
+
exec,
|
|
508
|
+
start,
|
|
509
|
+
pty,
|
|
510
|
+
files,
|
|
511
|
+
tunnels: tunnelsOf,
|
|
512
|
+
connectToken: Effect.fn(function* (options = {}) {
|
|
513
|
+
const response = yield* ops.createConnectToken({
|
|
514
|
+
sandboxId,
|
|
515
|
+
port: options.port,
|
|
516
|
+
userMetadata: options.userMetadata,
|
|
517
|
+
});
|
|
518
|
+
if (!response.url || !response.token) {
|
|
519
|
+
return yield* new SandboxUnexpectedResponse({ message: "Modal returned no connect token" });
|
|
520
|
+
}
|
|
521
|
+
return { url: response.url, token: response.token };
|
|
522
|
+
}),
|
|
523
|
+
snapshotFilesystem: (_timeout) => viaRouter(routerOps.snapshotFilesystem, (op, task) => Effect.flatMap(Effect.sync(() => SecureRandom.uuidV4Unsafe()),
|
|
524
|
+
// -1: the snapshot image never expires.
|
|
525
|
+
(snapshotId) => op({ taskId: task, snapshotId, ttlSeconds: "-1" }))).pipe(Effect.flatMap((response) => response.imageId
|
|
526
|
+
? Effect.succeed({ imageId: response.imageId })
|
|
527
|
+
: Effect.fail(new SandboxUnexpectedResponse({
|
|
528
|
+
message: `Filesystem snapshot of ${sandboxId} returned no image`,
|
|
529
|
+
})))),
|
|
530
|
+
snapshotMemory: () => viaRouter(routerOps.snapshotMemory, (op, task) => Effect.flatMap(Effect.sync(() => SecureRandom.uuidV4Unsafe()), (idempotencyKey) => op({ taskId: task, idempotencyKey }))).pipe(Effect.flatMap((response) => response.snapshotId
|
|
531
|
+
? Effect.succeed({ snapshotId: response.snapshotId })
|
|
532
|
+
: Effect.fail(new SandboxUnexpectedResponse({ message: "No snapshot id" })))),
|
|
533
|
+
snapshotDirectory: (path) => viaRouter(routerOps.snapshotDirectory, (op, task) => op({ taskId: task, path })).pipe(Effect.flatMap((response) => response.imageId
|
|
534
|
+
? Effect.succeed({ imageId: response.imageId })
|
|
535
|
+
: Effect.fail(new SandboxUnexpectedResponse({ message: `No image for ${path}` })))),
|
|
536
|
+
mountDirectory: (path, snapshot) => viaRouter(routerOps.mountDirectory, (op, task) => op({ taskId: task, path, imageId: snapshot.imageId })).pipe(Effect.asVoid),
|
|
537
|
+
setNetworkAccess: (access) => viaRouter(routerOps.setNetworkAccess, (op, task) => op({ taskId: task, networkAccess: runningNetworkAccessOf(access) })).pipe(Effect.asVoid),
|
|
538
|
+
setOutboundPolicy: Effect.fn(function* (policy) {
|
|
539
|
+
yield* ops.setOutboundPolicy({
|
|
540
|
+
sandboxId,
|
|
541
|
+
outboundPolicy: outboundPolicyOf(policy),
|
|
542
|
+
});
|
|
543
|
+
}),
|
|
544
|
+
setTags: Effect.fn(function* (tags) {
|
|
545
|
+
yield* ops.setTags({
|
|
546
|
+
sandboxId,
|
|
547
|
+
environmentName: environmentOf(target.environment),
|
|
548
|
+
tags: Object.entries(tags).map(([tagName, tagValue]) => ({ tagName, tagValue })),
|
|
549
|
+
});
|
|
550
|
+
}),
|
|
551
|
+
getTags: Effect.fn(function* () {
|
|
552
|
+
const { tags } = yield* ops.getTags({ sandboxId });
|
|
553
|
+
return Object.fromEntries((tags ?? []).map((t) => [t.tagName ?? "", t.tagValue ?? ""]));
|
|
554
|
+
}),
|
|
555
|
+
setName: Effect.fn(function* (name) {
|
|
556
|
+
yield* ops.setName({ sandboxId, name });
|
|
557
|
+
}),
|
|
558
|
+
resourceUsage: Effect.fn(function* () {
|
|
559
|
+
const usage = yield* ops.getResourceUsage({ sandboxId });
|
|
560
|
+
return {
|
|
561
|
+
cpuSeconds: Number(usage.cpuCoreNanosecs ?? 0) / 1e9,
|
|
562
|
+
memoryGibSeconds: Number(usage.memGibNanosecs ?? 0) / 1e9,
|
|
563
|
+
gpuSeconds: Number(usage.gpuNanosecs ?? 0) / 1e9,
|
|
564
|
+
};
|
|
565
|
+
}),
|
|
566
|
+
logs: Effect.fn(function* (options = {}) {
|
|
567
|
+
const { taskId: id, at } = yield* routerAccess;
|
|
568
|
+
const read = yield* routerOps.mainStdio(at);
|
|
569
|
+
const chunks = yield* read({
|
|
570
|
+
taskId: id,
|
|
571
|
+
offset: "0",
|
|
572
|
+
fileDescriptor: "SANDBOX_STDIO_FILE_DESCRIPTOR_STDOUT",
|
|
573
|
+
}).pipe(Stream.map((item) => Buffer.from(item.data, "base64")), Stream.interruptWhen(Effect.sleep(`${seconds(options.timeout) ?? 5} seconds`)), Stream.runCollect);
|
|
574
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
575
|
+
}),
|
|
576
|
+
wait: Effect.fn(function* (timeout) {
|
|
577
|
+
const { result } = yield* ops.wait({
|
|
578
|
+
sandboxId,
|
|
579
|
+
timeout: seconds(timeout) ?? 0,
|
|
580
|
+
});
|
|
581
|
+
return {
|
|
582
|
+
exitCode: result?.exitcode,
|
|
583
|
+
status: result?.status ?? "GENERIC_STATUS_UNSPECIFIED",
|
|
584
|
+
};
|
|
585
|
+
}),
|
|
586
|
+
getTcpPort,
|
|
587
|
+
terminate: Effect.fn(function* () {
|
|
588
|
+
yield* ops
|
|
589
|
+
.terminate({ sandboxId })
|
|
590
|
+
.pipe(Effect.catchTag("SandboxNotFound", () => Effect.void));
|
|
591
|
+
}),
|
|
592
|
+
};
|
|
593
|
+
return handle;
|
|
594
|
+
};
|
|
595
|
+
/**
|
|
596
|
+
* Create a sandbox in `target`'s app and return its handle. The one
|
|
597
|
+
* implementation behind `CreateSandbox` and warm-base image builds.
|
|
598
|
+
*/
|
|
599
|
+
export const createSandbox = Effect.fn(function* (ops, target, options = {}) {
|
|
600
|
+
const imageId = yield* resolveSandboxImage(ops, target, options.image);
|
|
601
|
+
const program = target.program;
|
|
602
|
+
const withProgram = program
|
|
603
|
+
? {
|
|
604
|
+
...options,
|
|
605
|
+
command: options.command ?? program.command,
|
|
606
|
+
secrets: [{ secretId: program.secretId }, ...(options.secrets ?? [])],
|
|
607
|
+
encryptedPorts: [...new Set([program.port, ...(options.encryptedPorts ?? [])])],
|
|
608
|
+
}
|
|
609
|
+
: options;
|
|
610
|
+
const own = yield* modalMountsOf(options.mounts);
|
|
611
|
+
const mounts = {
|
|
612
|
+
volumeMounts: [...(program?.mounts?.volumeMounts ?? []), ...own.volumeMounts],
|
|
613
|
+
cloudBucketMounts: [...(program?.mounts?.cloudBucketMounts ?? []), ...own.cloudBucketMounts],
|
|
614
|
+
};
|
|
615
|
+
const created = yield* ops.create({
|
|
616
|
+
appId: target.appId,
|
|
617
|
+
definition: definitionOf(imageId, withProgram, mounts),
|
|
618
|
+
tags: Object.entries(options.tags ?? {}).map(([tagName, tagValue]) => ({ tagName, tagValue })),
|
|
619
|
+
});
|
|
620
|
+
if (!created.sandboxId) {
|
|
621
|
+
return yield* new SandboxUnexpectedResponse({ message: "Modal returned no sandbox id" });
|
|
622
|
+
}
|
|
623
|
+
return sandboxHandle(ops, created.sandboxId, target);
|
|
624
|
+
});
|
|
625
|
+
/** A running sandbox of `target`'s app by name, or `undefined`. */
|
|
626
|
+
export const sandboxFromName = Effect.fn(function* (ops, target, name) {
|
|
627
|
+
const found = yield* ops
|
|
628
|
+
.getFromName({
|
|
629
|
+
sandboxName: name,
|
|
630
|
+
appName: target.appName,
|
|
631
|
+
environmentName: environmentOf(target.environment),
|
|
632
|
+
})
|
|
633
|
+
.pipe(Effect.catchTag("SandboxNotFound", () => Effect.undefined));
|
|
634
|
+
return found?.sandboxId ? sandboxHandle(ops, found.sandboxId, target) : undefined;
|
|
635
|
+
});
|
|
636
|
+
/** Running sandboxes of `target`'s app, optionally filtered by tags. */
|
|
637
|
+
export const listSandboxes = Effect.fn(function* (ops, target, options = {}) {
|
|
638
|
+
const { sandboxes } = yield* ops.list({
|
|
639
|
+
appId: target.appId,
|
|
640
|
+
environmentName: environmentOf(target.environment),
|
|
641
|
+
includeFinished: options.includeFinished ?? false,
|
|
642
|
+
tags: Object.entries(options.tags ?? {}).map(([tagName, tagValue]) => ({ tagName, tagValue })),
|
|
643
|
+
});
|
|
644
|
+
return (sandboxes ?? []).flatMap((info) => info.id
|
|
645
|
+
? [
|
|
646
|
+
{
|
|
647
|
+
sandboxId: info.id,
|
|
648
|
+
name: info.name || undefined,
|
|
649
|
+
createdAt: info.createdAt,
|
|
650
|
+
tags: Object.fromEntries((info.tags ?? []).map((t) => [t.tagName ?? "", t.tagValue ?? ""])),
|
|
651
|
+
},
|
|
652
|
+
]
|
|
653
|
+
: []);
|
|
654
|
+
});
|
|
655
|
+
/** Restore a memory snapshot into a new sandbox. */
|
|
656
|
+
export const restoreSandbox = Effect.fn(function* (ops, target, snapshot, options = {}) {
|
|
657
|
+
const restored = yield* ops.restore({
|
|
658
|
+
snapshotId: snapshot.snapshotId,
|
|
659
|
+
sandboxNameOverride: options.name,
|
|
660
|
+
sandboxNameOverrideType: options.name ? "SANDBOX_NAME_OVERRIDE_TYPE_STRING" : undefined,
|
|
661
|
+
});
|
|
662
|
+
if (!restored.sandboxId) {
|
|
663
|
+
return yield* new SandboxUnexpectedResponse({ message: "Modal returned no restored sandbox" });
|
|
664
|
+
}
|
|
665
|
+
return sandboxHandle(ops, restored.sandboxId, target);
|
|
666
|
+
});
|
|
667
|
+
/** Modal's session limits for persistent sandboxes. */
|
|
668
|
+
const PERSISTENT_SESSION = { timeout: 60 * 60, idleTimeout: 5 * 60 };
|
|
669
|
+
/** The handle for an existing persistent sandbox id. */
|
|
670
|
+
export const persistentSandboxHandle = (ops, persistentSandboxId, target) => ({
|
|
671
|
+
persistentSandboxId,
|
|
672
|
+
session: Effect.fn(function* () {
|
|
673
|
+
const running = yield* ops.getPersistent({ persistentSandboxId });
|
|
674
|
+
if (running.sandboxId)
|
|
675
|
+
return sandboxHandle(ops, running.sandboxId, target);
|
|
676
|
+
// A paused box resumes from its last session's filesystem. Modal answers
|
|
677
|
+
// busy while the previous session is still saving it.
|
|
678
|
+
const resumed = yield* ops.resumePersistent({ persistentSandboxId }).pipe(Effect.retry({
|
|
679
|
+
while: (error) => error._tag === "PersistentSandboxBusy",
|
|
680
|
+
schedule: Schedule.spaced("1 second"),
|
|
681
|
+
times: 60,
|
|
682
|
+
}));
|
|
683
|
+
if (!resumed.sandboxId) {
|
|
684
|
+
return yield* new SandboxUnexpectedResponse({
|
|
685
|
+
message: `Modal returned no session for persistent sandbox ${persistentSandboxId}`,
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
return sandboxHandle(ops, resumed.sandboxId, target);
|
|
689
|
+
}),
|
|
690
|
+
terminate: Effect.fn(function* () {
|
|
691
|
+
yield* ops
|
|
692
|
+
.terminatePersistent({ persistentSandboxId })
|
|
693
|
+
.pipe(Effect.catchTag("PersistentSandboxNotFound", () => Effect.void));
|
|
694
|
+
}),
|
|
695
|
+
});
|
|
696
|
+
/** Create a persistent sandbox in `target`'s app. */
|
|
697
|
+
export const createPersistentSandbox = Effect.fn(function* (ops, target, options = {}) {
|
|
698
|
+
const imageId = yield* resolveSandboxImage(ops, target, options.image);
|
|
699
|
+
const created = yield* ops.createPersistent({
|
|
700
|
+
appId: target.appId,
|
|
701
|
+
definition: definitionOf(imageId, { ...options, ...PERSISTENT_SESSION }, yield* modalMountsOf(options.mounts)),
|
|
702
|
+
});
|
|
703
|
+
if (!created.persistentSandboxId) {
|
|
704
|
+
return yield* new SandboxUnexpectedResponse({
|
|
705
|
+
message: "Modal returned no persistent sandbox id",
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
return persistentSandboxHandle(ops, created.persistentSandboxId, target);
|
|
709
|
+
});
|
|
710
|
+
//# sourceMappingURL=SandboxClient.js.map
|