daytona 0.200.1 → 0.201.0

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.
@@ -0,0 +1,279 @@
1
+ # Copyright Daytona Platforms Inc.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # frozen_string_literal: true
5
+
6
+ require 'json'
7
+
8
+ module Daytona
9
+ module Sdk # rubocop:disable Metrics/ModuleLength
10
+ # ApiError classes raised by the generated OpenAPI clients. Kept here so
11
+ # the error module can resolve them without depending on `sdk.rb`.
12
+ API_ERROR_CLASSES = [DaytonaApiClient::ApiError, DaytonaToolboxApiClient::ApiError].freeze
13
+
14
+ # Wire-format `source` values set by the translation layer when a
15
+ # Daytona service stamps them on the wire envelope. `nil` source means
16
+ # the response did not carry a structured envelope (treat as opaque).
17
+ SOURCE_API = 'DAYTONA_API'
18
+ SOURCE_DAEMON = 'DAYTONA_DAEMON'
19
+ SOURCE_PROXY = 'DAYTONA_PROXY'
20
+
21
+ # ---------------------------------------------------------------------
22
+ # Base
23
+ # ---------------------------------------------------------------------
24
+
25
+ # Base class for every error raised by the Daytona SDK.
26
+ #
27
+ # @example Catching any SDK error
28
+ # begin
29
+ # daytona.create(params)
30
+ # rescue Daytona::Sdk::Error => e
31
+ # puts e.status_code, e.code, e.source
32
+ # end
33
+ class Error < StandardError
34
+ def initialize(message = nil, status_code: nil, code: nil, source: nil, headers: nil)
35
+ super(message)
36
+ @status_code = status_code
37
+ @code = code
38
+ @source = source
39
+ @headers = headers
40
+ end
41
+
42
+ def status_code = @status_code || metadata_from_cause[:status_code]
43
+
44
+ def code = @code || metadata_from_cause[:code]
45
+
46
+ def headers = @headers || metadata_from_cause[:headers] || {}
47
+
48
+ # Returns the originating service, or `nil` if unknown. Falls back to
49
+ # metadata carried by `cause` so a re-raised ApiError keeps its
50
+ # server-stamped source.
51
+ def source = @source || metadata_from_cause[:source]
52
+
53
+ private
54
+
55
+ def metadata_from_cause
56
+ @metadata_from_cause ||= Sdk.api_error_details(cause)
57
+ end
58
+ end
59
+
60
+ # ---------------------------------------------------------------------
61
+ # HTTP status-class errors
62
+ # ---------------------------------------------------------------------
63
+
64
+ # HTTP 400 — request was rejected as malformed or invalid.
65
+ class BadRequestError < Error; end
66
+
67
+ # HTTP 401 — authentication failed or credentials missing.
68
+ class AuthenticationError < Error; end
69
+
70
+ # HTTP 403 — caller is authenticated but not allowed.
71
+ class ForbiddenError < Error; end
72
+
73
+ # HTTP 404 — target resource does not exist.
74
+ class NotFoundError < Error; end
75
+
76
+ # HTTP 408 / 504 / client-side timeouts.
77
+ class TimeoutError < Error; end
78
+
79
+ # HTTP 409 — request conflicts with current resource state.
80
+ class ConflictError < Error; end
81
+
82
+ # HTTP 410 — resource is permanently gone.
83
+ class GoneError < Error; end
84
+
85
+ # HTTP 422 — request is well-formed but semantically invalid.
86
+ class UnprocessableEntityError < Error; end
87
+
88
+ # HTTP 429 — rate limit was exceeded.
89
+ class RateLimitError < Error; end
90
+
91
+ # Generic 5xx fallback when a more specific class doesn't apply.
92
+ class ServerError < Error; end
93
+
94
+ # HTTP 500 — server-side bug or unhandled condition.
95
+ class InternalServerError < ServerError; end
96
+
97
+ # HTTP 502 — an upstream dependency rejected or dropped the request.
98
+ class BadGatewayError < ServerError; end
99
+
100
+ # HTTP 503 — the service is temporarily refusing traffic.
101
+ class ServiceUnavailableError < ServerError; end
102
+
103
+ # Transport-level failure (no HTTP response received).
104
+ class ConnectionError < Error; end
105
+
106
+ # Transport-level timeout. Subclass of ConnectionError so callers that
107
+ # catch the broader connection-failure category also match.
108
+ class ConnectionTimeoutError < ConnectionError; end
109
+
110
+ # ---------------------------------------------------------------------
111
+ # Domain subclasses — each inherits from the HTTP-status parent that
112
+ # matches its server-side status code.
113
+ # ---------------------------------------------------------------------
114
+
115
+ # Daemon: git
116
+ class GitAuthFailedError < AuthenticationError; end
117
+ class GitRepoNotFoundError < NotFoundError; end
118
+ class GitBranchNotFoundError < NotFoundError; end
119
+ class GitBranchExistsError < ConflictError; end
120
+ class GitPushRejectedError < ConflictError; end
121
+ class GitDirtyWorktreeError < ConflictError; end
122
+ class GitMergeConflictError < ConflictError; end
123
+
124
+ # Daemon: filesystem
125
+ class FileNotFoundError < NotFoundError; end
126
+ class FileAccessDeniedError < ForbiddenError; end
127
+
128
+ # Daemon: LSP
129
+ class LspServerNotInitializedError < BadRequestError; end
130
+
131
+ # Daemon: process / session
132
+ class ProcessExecutionTimeoutError < TimeoutError; end
133
+ class ProcessNotFoundError < NotFoundError; end
134
+ class SessionEndedError < GoneError; end
135
+ class CommandAlreadyCompletedError < GoneError; end
136
+
137
+ # Daemon: computer-use
138
+ class A11yUnavailableError < ServiceUnavailableError; end
139
+ class RecordingStillActiveError < ConflictError; end
140
+ class RecordingFfmpegNotFoundError < ServiceUnavailableError; end
141
+
142
+ # ---------------------------------------------------------------------
143
+ # Routing tables
144
+ # ---------------------------------------------------------------------
145
+
146
+ STATUS_CODE_TO_ERROR = {
147
+ 400 => BadRequestError,
148
+ 401 => AuthenticationError,
149
+ 403 => ForbiddenError,
150
+ 404 => NotFoundError,
151
+ 408 => TimeoutError,
152
+ 409 => ConflictError,
153
+ 410 => GoneError,
154
+ 422 => UnprocessableEntityError,
155
+ 429 => RateLimitError,
156
+ 500 => InternalServerError,
157
+ 502 => BadGatewayError,
158
+ 503 => ServiceUnavailableError,
159
+ 504 => TimeoutError
160
+ }.freeze
161
+
162
+ # (source, code) tuple → exception class. Resolved BEFORE the status
163
+ # code, so a server-stamped domain code always wins over the generic
164
+ # status class.
165
+ CODE_TO_ERROR = {
166
+ # Daemon: git
167
+ [SOURCE_DAEMON, 'GIT_AUTH_FAILED'] => GitAuthFailedError,
168
+ [SOURCE_DAEMON, 'GIT_REPO_NOT_FOUND'] => GitRepoNotFoundError,
169
+ [SOURCE_DAEMON, 'GIT_BRANCH_NOT_FOUND'] => GitBranchNotFoundError,
170
+ [SOURCE_DAEMON, 'GIT_BRANCH_EXISTS'] => GitBranchExistsError,
171
+ [SOURCE_DAEMON, 'GIT_PUSH_REJECTED'] => GitPushRejectedError,
172
+ [SOURCE_DAEMON, 'GIT_DIRTY_WORKTREE'] => GitDirtyWorktreeError,
173
+ [SOURCE_DAEMON, 'GIT_MERGE_CONFLICT'] => GitMergeConflictError,
174
+
175
+ # Daemon: filesystem
176
+ [SOURCE_DAEMON, 'FILE_NOT_FOUND'] => FileNotFoundError,
177
+ [SOURCE_DAEMON, 'FILE_ACCESS_DENIED'] => FileAccessDeniedError,
178
+
179
+ # Daemon: LSP
180
+ [SOURCE_DAEMON, 'LSP_SERVER_NOT_INITIALIZED'] => LspServerNotInitializedError,
181
+
182
+ # Daemon: process / session
183
+ [SOURCE_DAEMON, 'PROCESS_EXECUTION_TIMEOUT'] => ProcessExecutionTimeoutError,
184
+ [SOURCE_DAEMON, 'PROCESS_NOT_FOUND'] => ProcessNotFoundError,
185
+ [SOURCE_DAEMON, 'SESSION_ENDED'] => SessionEndedError,
186
+ [SOURCE_DAEMON, 'COMMAND_ALREADY_COMPLETED'] => CommandAlreadyCompletedError,
187
+
188
+ # Daemon: computer-use
189
+ [SOURCE_DAEMON, 'A11Y_UNAVAILABLE'] => A11yUnavailableError,
190
+ [SOURCE_DAEMON, 'RECORDING_STILL_ACTIVE'] => RecordingStillActiveError,
191
+ [SOURCE_DAEMON, 'RECORDING_FFMPEG_NOT_FOUND'] => RecordingFfmpegNotFoundError
192
+ }.freeze
193
+
194
+ # ---------------------------------------------------------------------
195
+ # Public translation helpers (module-level functions on Daytona::Sdk)
196
+ # ---------------------------------------------------------------------
197
+
198
+ # Translate an OpenAPI-client error into the most specific Daytona SDK
199
+ # exception. Accepts an optional `prefix` that's prepended to the
200
+ # message for context (e.g. "Failed to create sandbox"). When `error`
201
+ # is already an `Sdk::Error` (e.g. raised by the streaming transfer
202
+ # helpers for cancel/timeout), its class is preserved and only the
203
+ # message is prefixed.
204
+ def self.wrap_error(error, prefix = nil)
205
+ if error.is_a?(Error)
206
+ message = prefix ? "#{prefix}: #{error.message}" : error.message
207
+ return error.class.new(message, status_code: error.status_code, code: error.code,
208
+ source: error.source, headers: error.headers)
209
+ end
210
+
211
+ details = api_error_details(error)
212
+ base_message = parsed_message(error) || error.message
213
+ message = prefix ? "#{prefix}: #{base_message}" : base_message
214
+ error_class_for(details).new(message, **details.slice(:status_code, :code, :source, :headers))
215
+ end
216
+
217
+ # Extract status code, code, source and headers from a raised OpenAPI
218
+ # error. Returns an empty hash when the error is not one of the
219
+ # generated client types.
220
+ def self.api_error_details(error)
221
+ return {} unless API_ERROR_CLASSES.any? { |c| error.is_a?(c) }
222
+
223
+ data = parse_error_body(error.respond_to?(:response_body) ? error.response_body : nil)
224
+ {
225
+ status_code: error.respond_to?(:code) ? error.code : nil,
226
+ code: data[:code],
227
+ source: data[:source],
228
+ headers: error.respond_to?(:response_headers) ? error.response_headers : nil
229
+ }
230
+ end
231
+
232
+ # Choose the exception class for a parsed error: (source, code) match
233
+ # wins, then HTTP status code, then the base Error.
234
+ def self.error_class_for(details)
235
+ code = details[:code]
236
+ source = details[:source]
237
+ if code && source
238
+ cls = CODE_TO_ERROR[[source, code]]
239
+ return cls if cls
240
+ end
241
+ status_code = details[:status_code]
242
+ exact_status_error = STATUS_CODE_TO_ERROR[status_code]
243
+ return exact_status_error if exact_status_error
244
+
245
+ return ServerError if status_code.is_a?(Integer) && status_code >= 500
246
+
247
+ Error
248
+ end
249
+
250
+ def self.parse_error_body(response_body)
251
+ return {} if response_body.nil? || response_body.empty?
252
+
253
+ data = JSON.parse(response_body)
254
+ return {} unless data.is_a?(Hash)
255
+
256
+ {
257
+ message: string_or_nil(data['message']) || string_or_nil(data['error']),
258
+ code: string_or_nil(data['code'] || data['error_code']),
259
+ source: string_or_nil(data['source'])
260
+ }
261
+ rescue JSON::ParserError
262
+ {}
263
+ end
264
+
265
+ # @api private
266
+ def self.parsed_message(error)
267
+ return nil unless API_ERROR_CLASSES.any? { |c| error.is_a?(c) }
268
+ return nil unless error.respond_to?(:response_body)
269
+
270
+ parse_error_body(error.response_body)[:message]
271
+ end
272
+
273
+ def self.string_or_nil(value)
274
+ value.is_a?(String) && !value.empty? ? value : nil
275
+ end
276
+
277
+ private_class_method :error_class_for, :parse_error_body, :parsed_message, :string_or_nil
278
+ end
279
+ end
@@ -0,0 +1,131 @@
1
+ # Copyright Daytona Platforms Inc.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # frozen_string_literal: true
5
+
6
+ # Patches the OpenAPI-generated `download_file` and `call_api` helpers in both
7
+ # API clients so that streaming responses (return_type == 'File') do not lose
8
+ # the response body when the server returns an error status.
9
+ #
10
+ # Background:
11
+ # For File downloads the generated `download_file` attaches Typhoeus
12
+ # `on_body` callbacks to stream the response into a Tempfile. The presence
13
+ # of `on_body` prevents Typhoeus from populating `response.body`, which
14
+ # means the daemon's structured error envelope (code/source/message) is
15
+ # discarded when the response is an error. The generated `call_api` then
16
+ # raises `ApiError` with an empty `response_body`.
17
+ #
18
+ # Fix:
19
+ # * In `download_file`, defer tempfile creation until `on_headers` and
20
+ # inspect the status code. For 2xx responses, behave exactly like the
21
+ # upstream code. For non-2xx responses, accumulate the body into a
22
+ # buffer stored as an instance variable on the ApiClient.
23
+ # * In `call_api`, rescue the `ApiError`, and if our buffer is populated,
24
+ # re-raise with `response_body` set to the buffered envelope.
25
+
26
+ require 'tempfile'
27
+
28
+ module Daytona
29
+ module Sdk
30
+ # rubocop:disable Metrics/AbcSize, Metrics/BlockLength, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
31
+ module FileDownloadPatch
32
+ def self.apply!(api_client_class, api_error_class)
33
+ return if api_client_class.method_defined?(:_daytona_orig_call_api)
34
+
35
+ api_client_class.class_eval do
36
+ define_method(:_daytona_error_body_key) do
37
+ @daytona_error_body_key ||= :"daytona_file_download_error_body_#{object_id}"
38
+ end
39
+
40
+ define_method(:download_file) do |request, &block|
41
+ tempfile = nil
42
+ encoding = nil
43
+ stream_to_tempfile = false
44
+ error_body = String.new.b
45
+ Thread.current.thread_variable_set(_daytona_error_body_key, nil)
46
+
47
+ request.on_headers do |response|
48
+ stream_to_tempfile = response.code && response.code >= 200 && response.code < 300
49
+ next unless stream_to_tempfile
50
+
51
+ content_disposition = response.headers['Content-Disposition']
52
+ if content_disposition && content_disposition =~ /filename=/i
53
+ filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1]
54
+ prefix = sanitize_filename(filename)
55
+ else
56
+ prefix = 'download-'
57
+ end
58
+ prefix += '-' unless prefix.end_with?('-')
59
+ encoding = response.body.encoding
60
+ tempfile = Tempfile.open(prefix, @config.temp_folder_path, encoding: encoding)
61
+ end
62
+
63
+ request.on_body do |chunk|
64
+ if stream_to_tempfile
65
+ chunk.force_encoding(encoding)
66
+ tempfile.write(chunk)
67
+ else
68
+ error_body << chunk.b
69
+ end
70
+ end
71
+
72
+ request.on_complete do
73
+ if stream_to_tempfile
74
+ if tempfile.nil?
75
+ raise api_error_class,
76
+ "Failed to create the tempfile based on the HTTP response from the server: #{request.inspect}"
77
+ end
78
+ tempfile.close
79
+ @config.logger.info(
80
+ "Temp file written to #{tempfile.path}, please copy the file to a proper folder " \
81
+ "with e.g. `FileUtils.cp(tempfile.path, '/new/file/path')` otherwise the temp file " \
82
+ 'will be deleted automatically with GC. It\'s also recommended to delete the temp file ' \
83
+ 'explicitly with `tempfile.delete`'
84
+ )
85
+ block&.call(tempfile)
86
+ else
87
+ Thread.current.thread_variable_set(_daytona_error_body_key, error_body) unless error_body.empty?
88
+ end
89
+ end
90
+ end
91
+
92
+ alias_method :_daytona_orig_call_api, :call_api
93
+
94
+ define_method(:call_api) do |http_method, path, opts = {}|
95
+ _daytona_orig_call_api(http_method, path, opts)
96
+ rescue api_error_class => e
97
+ error_body = Thread.current.thread_variable_get(_daytona_error_body_key)
98
+ if opts[:return_type] == 'File' && error_body && !error_body.empty?
99
+ new_err = api_error_class.new(
100
+ code: e.code,
101
+ response_headers: e.response_headers,
102
+ response_body: error_body
103
+ )
104
+ raise new_err, e.message
105
+ end
106
+ raise
107
+ ensure
108
+ Thread.current.thread_variable_set(_daytona_error_body_key, nil)
109
+ end
110
+
111
+ private :_daytona_error_body_key
112
+ end
113
+ end
114
+ end
115
+ # rubocop:enable Metrics/AbcSize, Metrics/BlockLength, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
116
+ end
117
+ end
118
+
119
+ if Object.const_defined?(:DaytonaApiClient) &&
120
+ DaytonaApiClient.const_defined?(:ApiClient) &&
121
+ DaytonaApiClient.const_defined?(:ApiError)
122
+ Daytona::Sdk::FileDownloadPatch.apply!(DaytonaApiClient::ApiClient, DaytonaApiClient::ApiError)
123
+ end
124
+
125
+ if Object.const_defined?(:DaytonaToolboxApiClient) &&
126
+ DaytonaToolboxApiClient.const_defined?(:ApiClient) &&
127
+ DaytonaToolboxApiClient.const_defined?(:ApiError)
128
+ Daytona::Sdk::FileDownloadPatch.apply!(
129
+ DaytonaToolboxApiClient::ApiClient, DaytonaToolboxApiClient::ApiError
130
+ )
131
+ end
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Daytona
7
7
  module Sdk
8
- VERSION = '0.200.1'
8
+ VERSION = '0.201.0'
9
9
  end
10
10
  end
data/lib/daytona/sdk.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  # Copyright Daytona Platforms Inc.
4
4
  # SPDX-License-Identifier: Apache-2.0
5
5
 
6
+ require 'json'
6
7
  require 'logger'
7
8
 
8
9
  require 'daytona_api_client'
@@ -12,6 +13,9 @@ require 'toml'
12
13
  require 'websocket-client-simple'
13
14
 
14
15
  require_relative 'sdk/version'
16
+ require_relative 'sdk/errors'
17
+ require_relative 'sdk/deprecated'
18
+ require_relative 'sdk/file_download_patch'
15
19
  require_relative 'config'
16
20
  require_relative 'otel'
17
21
  require_relative 'common/charts'
@@ -47,15 +51,9 @@ require_relative 'process'
47
51
 
48
52
  module Daytona
49
53
  module Sdk
50
- class Error < StandardError; end
51
- class TimeoutError < Error; end
52
- class AuthenticationError < Error; end
53
- class ForbiddenError < Error; end
54
- class NotFoundError < Error; end
55
- class ConflictError < Error; end
56
- class ValidationError < Error; end
57
- class RateLimitError < Error; end
58
- class ServerError < Error; end
54
+ # The error hierarchy and translation helpers live in `sdk/errors.rb`.
55
+ # This file just provides cross-cutting bits that need to be loaded
56
+ # alongside them.
59
57
 
60
58
  def self.logger = @logger ||= Logger.new($stdout, level: Logger::INFO)
61
59
  end
@@ -147,7 +147,8 @@ module Daytona
147
147
  aws_access_key_id: push_access_creds.access_key,
148
148
  aws_secret_access_key: push_access_creds.secret,
149
149
  aws_session_token: push_access_creds.session_token,
150
- bucket_name: push_access_creds.bucket
150
+ bucket_name: push_access_creds.bucket,
151
+ region: push_access_creds.region
151
152
  )
152
153
 
153
154
  image.context_list.map do |context|
@@ -0,0 +1,56 @@
1
+ # Copyright Daytona Platforms Inc.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ # frozen_string_literal: true
5
+
6
+ require 'base64'
7
+ require 'openssl'
8
+ require 'uri'
9
+
10
+ module Daytona
11
+ module Utils
12
+ module FileUrlSigning
13
+ SIGNATURE_V1_PREFIX = 'v1_'
14
+ private_constant :SIGNATURE_V1_PREFIX
15
+
16
+ DEFAULT_TTL_SECONDS = 3600
17
+ private_constant :DEFAULT_TTL_SECONDS
18
+
19
+ module_function
20
+
21
+ def compute_file_url_signature(signing_key, method, path, expires)
22
+ canonical = "v1:files:#{method}:#{path}:#{expires}"
23
+ digest = OpenSSL::HMAC.digest('sha256', signing_key, canonical)
24
+
25
+ "#{SIGNATURE_V1_PREFIX}#{Base64.urlsafe_encode64(digest, padding: false)}"
26
+ end
27
+
28
+ def resolve_expires(ttl_seconds)
29
+ return Time.now.to_i + DEFAULT_TTL_SECONDS if ttl_seconds.nil?
30
+
31
+ return 0 if ttl_seconds <= 0
32
+
33
+ Time.now.to_i + ttl_seconds
34
+ end
35
+
36
+ def build_signed_file_url(toolbox_proxy_url, sandbox_id, operation_path, method, file_path, signing_key,
37
+ ttl_seconds)
38
+ if signing_key.nil? || signing_key.empty?
39
+ raise Daytona::Sdk::Error,
40
+ 'Sandbox signing key is not available. Call refresh or fetch the sandbox by ID to load it.'
41
+ end
42
+
43
+ if toolbox_proxy_url.nil? || toolbox_proxy_url.empty?
44
+ raise Daytona::Sdk::Error,
45
+ 'Sandbox toolbox proxy URL is not available. Call refresh or fetch the sandbox by ID to load it.'
46
+ end
47
+
48
+ expires = resolve_expires(ttl_seconds)
49
+ signature = compute_file_url_signature(signing_key, method, file_path, expires)
50
+ query = URI.encode_www_form(path: file_path, expires: expires.to_s, signature:)
51
+
52
+ "#{toolbox_proxy_url.sub(%r{/+\z}, '')}/#{sandbox_id}#{operation_path}?#{query}"
53
+ end
54
+ end
55
+ end
56
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: daytona
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.200.1
4
+ version: 0.201.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daytona Platforms Inc.
@@ -85,56 +85,62 @@ dependencies:
85
85
  requirements:
86
86
  - - '='
87
87
  - !ruby/object:Gem::Version
88
- version: 0.200.1
88
+ version: 0.201.0
89
89
  type: :runtime
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
93
  - - '='
94
94
  - !ruby/object:Gem::Version
95
- version: 0.200.1
95
+ version: 0.201.0
96
96
  - !ruby/object:Gem::Dependency
97
97
  name: daytona_api_client
98
98
  requirement: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - '='
101
101
  - !ruby/object:Gem::Version
102
- version: 0.200.1
102
+ version: 0.201.0
103
103
  type: :runtime
104
104
  prerelease: false
105
105
  version_requirements: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - '='
108
108
  - !ruby/object:Gem::Version
109
- version: 0.200.1
109
+ version: 0.201.0
110
110
  - !ruby/object:Gem::Dependency
111
111
  name: daytona_toolbox_api_client
112
112
  requirement: !ruby/object:Gem::Requirement
113
113
  requirements:
114
114
  - - '='
115
115
  - !ruby/object:Gem::Version
116
- version: 0.200.1
116
+ version: 0.201.0
117
117
  type: :runtime
118
118
  prerelease: false
119
119
  version_requirements: !ruby/object:Gem::Requirement
120
120
  requirements:
121
121
  - - '='
122
122
  - !ruby/object:Gem::Version
123
- version: 0.200.1
123
+ version: 0.201.0
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: dotenv
126
126
  requirement: !ruby/object:Gem::Requirement
127
127
  requirements:
128
- - - "~>"
128
+ - - ">="
129
129
  - !ruby/object:Gem::Version
130
130
  version: '2.0'
131
+ - - "<"
132
+ - !ruby/object:Gem::Version
133
+ version: '4'
131
134
  type: :runtime
132
135
  prerelease: false
133
136
  version_requirements: !ruby/object:Gem::Requirement
134
137
  requirements:
135
- - - "~>"
138
+ - - ">="
136
139
  - !ruby/object:Gem::Version
137
140
  version: '2.0'
141
+ - - "<"
142
+ - !ruby/object:Gem::Version
143
+ version: '4'
138
144
  - !ruby/object:Gem::Dependency
139
145
  name: observer
140
146
  requirement: !ruby/object:Gem::Requirement
@@ -221,11 +227,15 @@ files:
221
227
  - lib/daytona/process.rb
222
228
  - lib/daytona/sandbox.rb
223
229
  - lib/daytona/sdk.rb
230
+ - lib/daytona/sdk/deprecated.rb
231
+ - lib/daytona/sdk/errors.rb
232
+ - lib/daytona/sdk/file_download_patch.rb
224
233
  - lib/daytona/sdk/version.rb
225
234
  - lib/daytona/secret.rb
226
235
  - lib/daytona/secret_service.rb
227
236
  - lib/daytona/snapshot_service.rb
228
237
  - lib/daytona/util.rb
238
+ - lib/daytona/utils/file_url_signing.rb
229
239
  - lib/daytona/volume.rb
230
240
  - lib/daytona/volume_service.rb
231
241
  - project.json