Class: Supabase::Storage::FileApi

Inherits:
Object
  • Object
show all
Includes:
Request
Defined in:
lib/supabase/storage/file_api.rb

Overview

All file-level operations scoped to one bucket — upload / download / list / remove / move / copy / info / exists, plus signed/public URL helpers. Mirrors storage3’s SyncBucketActionsMixin + SyncBucketProxy.

Constructed via Client#from(bucket_id).

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id, base_url, headers, session) ⇒ FileApi

Returns a new instance of FileApi.



24
25
26
27
28
29
# File 'lib/supabase/storage/file_api.rb', line 24

def initialize(id, base_url, headers, session)
  @id       = id
  @base_url = base_url.end_with?("/") ? base_url : "#{base_url}/"
  @headers  = headers
  @session  = session
end

Instance Attribute Details

#idObject (readonly)

Returns the value of attribute id.



22
23
24
# File 'lib/supabase/storage/file_api.rb', line 22

def id
  @id
end

Instance Method Details

#copy(from_path, to_path) ⇒ Object



110
111
112
113
# File 'lib/supabase/storage/file_api.rb', line 110

def copy(from_path, to_path)
  _request(:post, ["object", "copy"],
           json: { "bucketId" => @id, "sourceKey" => from_path, "destinationKey" => to_path })
end

#create_signed_upload_url(path, upsert: nil) ⇒ Object



182
183
184
185
186
187
188
189
190
191
192
# File 'lib/supabase/storage/file_api.rb', line 182

def create_signed_upload_url(path, upsert: nil)
  headers = upsert.nil? ? {} : { "x-upsert" => upsert.to_s }
  parts   = Utils.relative_path_to_parts(path)
  body    = _request(:post, ["object", "upload", "sign", @id, *parts], headers: headers)

  signed_url = "#{@base_url.chomp('/')}#{body['url']}"
  token = URI.decode_www_form(URI.parse(signed_url).query.to_s).to_h["token"]
  raise Errors::StorageError, "No token sent by the API" if token.nil? || token.empty?

  Types::SignedUploadURL.new(signed_url: signed_url, token: token, path: path)
end

#create_signed_url(path, expires_in:, download: nil, transform: nil) ⇒ Hash

Returns { “signedURL” => “…”, “signedUrl” => “…” }.

Parameters:

  • expires_in (Integer)

    seconds until the URL expires

  • download (Boolean, String, nil) (defaults to: nil)

    ‘true` to force browser download with the original filename, a String to override the filename, or nil to leave inline

Returns:

  • (Hash)

    { “signedURL” => “…”, “signedUrl” => “…” }



134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/supabase/storage/file_api.rb', line 134

def create_signed_url(path, expires_in:, download: nil, transform: nil)
  json = { "expiresIn" => expires_in.to_s }
  download_query = {}
  if download
    json["download"] = download
    download_query["download"] = download == true ? "" : download
  end
  json["transform"] = transform if transform

  parts = Utils.relative_path_to_parts(path)
  body  = _request(:post, ["object", "sign", @id, *parts], json: json)
  wrap_signed_url(body["signedURL"] || body["signedUrl"], download_query)
end

#create_signed_urls(paths, expires_in:, download: nil) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/supabase/storage/file_api.rb', line 148

def create_signed_urls(paths, expires_in:, download: nil)
  json = { "paths" => Array(paths), "expiresIn" => expires_in.to_s }
  download_query = {}
  if download
    json["download"] = download
    download_query["download"] = download == true ? "" : download
  end

  items = _request(:post, ["object", "sign", @id], json: json)
  Array(items).map do |item|
    wrapped = wrap_signed_url(item["signedURL"] || item["signedUrl"], download_query)
    {
      "error"     => item["error"],
      "path"      => item["path"],
      "signedURL" => wrapped["signedURL"],
      "signedUrl" => wrapped["signedURL"]
    }
  end
end

#download(path) ⇒ Object

—– Download —–



56
57
58
59
60
# File 'lib/supabase/storage/file_api.rb', line 56

def download(path)
  parts = Utils.relative_path_to_parts(path)
  response = _request(:get, ["object", @id, *parts], raw_response: true)
  response.body
end

#exists?(path) ⇒ Boolean

Returns:

  • (Boolean)


120
121
122
123
124
125
126
# File 'lib/supabase/storage/file_api.rb', line 120

def exists?(path)
  parts = Utils.relative_path_to_parts(path)
  response = _request(:head, ["object", @id, *parts], raw_response: true)
  response.status == 200
rescue Errors::StorageApiError
  false
end

#get_public_url(path, download: nil, transform: nil) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/supabase/storage/file_api.rb', line 168

def get_public_url(path, download: nil, transform: nil)
  download_query = {}
  if download
    download_query["download"] = download == true ? "" : download
  end

  render_path = transform ? %w[render image] : %w[object]
  transform_query = transform ? transform.transform_keys(&:to_s).transform_values(&:to_s) : {}
  query = download_query.merge(transform_query)

  parts = Utils.relative_path_to_parts(path)
  Utils.join_url(@base_url, [*render_path, "public", @id, *parts], query)
end

#info(path) ⇒ Object



115
116
117
118
# File 'lib/supabase/storage/file_api.rb', line 115

def info(path)
  parts = Utils.relative_path_to_parts(path)
  _request(:get, ["object", "info", @id, *parts])
end

#list(prefix = nil, limit: nil, offset: nil, sort_by: nil, search: nil) ⇒ Object

Parameters:

  • prefix (String, nil) (defaults to: nil)

    folder path to list under

  • limit (Integer) (defaults to: nil)
  • offset (Integer) (defaults to: nil)
  • sort_by (Hash) (defaults to: nil)

    order:

  • search (String, nil) (defaults to: nil)


69
70
71
72
73
74
75
76
77
# File 'lib/supabase/storage/file_api.rb', line 69

def list(prefix = nil, limit: nil, offset: nil, sort_by: nil, search: nil)
  body = Types::DEFAULT_SEARCH_OPTIONS.dup
  body["limit"]  = limit  unless limit.nil?
  body["offset"] = offset unless offset.nil?
  body["sortBy"] = stringify_sort_by(sort_by) if sort_by
  body["search"] = search unless search.nil?
  body["prefix"] = prefix || ""
  _request(:post, ["object", "list", @id], json: body, headers: { "Content-Type" => "application/json" })
end

#list_v2(prefix: nil, limit: nil, cursor: nil, with_delimiter: nil, sort_by: nil) ⇒ Types::SearchV2Result

Cursor-paginated list. Mirrors storage3’s list_v2 — only sends the keys the caller passed (no DEFAULT_SEARCH_OPTIONS merge).

Parameters:

  • prefix (String, nil) (defaults to: nil)
  • limit (Integer, nil) (defaults to: nil)
  • cursor (String, nil) (defaults to: nil)

    opaque cursor returned by a previous call

  • with_delimiter (Boolean, nil) (defaults to: nil)

    if true, server groups by “/” into folders

  • sort_by (Hash, nil) (defaults to: nil)

    order:

Returns:



87
88
89
90
91
92
93
94
95
96
97
# File 'lib/supabase/storage/file_api.rb', line 87

def list_v2(prefix: nil, limit: nil, cursor: nil, with_delimiter: nil, sort_by: nil)
  body = {}
  body["prefix"]         = prefix         unless prefix.nil?
  body["limit"]          = limit          unless limit.nil?
  body["cursor"]         = cursor         unless cursor.nil?
  body["with_delimiter"] = with_delimiter unless with_delimiter.nil?
  body["sortBy"]         = stringify_sort_by(sort_by) if sort_by
  data = _request(:post, ["object", "list-v2", @id], json: body,
                                                     headers: { "Content-Type" => "application/json" })
  Types::SearchV2Result.from_hash(data)
end

#move(from_path, to_path) ⇒ Object



105
106
107
108
# File 'lib/supabase/storage/file_api.rb', line 105

def move(from_path, to_path)
  _request(:post, ["object", "move"],
           json: { "bucketId" => @id, "sourceKey" => from_path, "destinationKey" => to_path })
end

#remove(paths) ⇒ Object

—– Remove / Move / Copy / Info / Exists —–



101
102
103
# File 'lib/supabase/storage/file_api.rb', line 101

def remove(paths)
  _request(:delete, ["object", @id], json: { "prefixes" => Array(paths) })
end

#update(path, file, content_type: nil, cache_control: nil, metadata: nil, headers: nil) ⇒ Object



47
48
49
50
51
52
# File 'lib/supabase/storage/file_api.rb', line 47

def update(path, file, content_type: nil, cache_control: nil, metadata: nil, headers: nil)
  # Per Python: PUT never sends x-upsert.
  upload_or_update(:put, path, file,
                   content_type: content_type, cache_control: cache_control,
                   upsert: false, metadata: , headers: headers, omit_upsert: true)
end

#upload(path, file, content_type: nil, cache_control: nil, upsert: false, metadata: nil, headers: nil) ⇒ Types::UploadResponse

Parameters:

  • path (String)

    destination path within the bucket (e.g. “folder/avatar.png”)

  • file (String, IO, Pathname)

    bytes / file-like object / path on disk

  • content_type (String, nil) (defaults to: nil)
  • cache_control (String, Integer, nil) (defaults to: nil)

    becomes “max-age=<n>”

  • upsert (Boolean) (defaults to: false)
  • metadata (Hash, nil) (defaults to: nil)

    base64-encoded into the x-metadata header

  • headers (Hash, nil) (defaults to: nil)

    extra HTTP headers to send

Returns:



41
42
43
44
45
# File 'lib/supabase/storage/file_api.rb', line 41

def upload(path, file, content_type: nil, cache_control: nil, upsert: false, metadata: nil, headers: nil)
  upload_or_update(:post, path, file,
                   content_type: content_type, cache_control: cache_control,
                   upsert: upsert, metadata: , headers: headers)
end

#upload_to_signed_url(path, token:, file:, content_type: nil, cache_control: nil, metadata: nil, headers: nil) ⇒ Object



194
195
196
197
198
199
200
# File 'lib/supabase/storage/file_api.rb', line 194

def upload_to_signed_url(path, token:, file:, content_type: nil, cache_control: nil, metadata: nil, headers: nil)
  parts = Utils.relative_path_to_parts(path)
  send_multipart(:put, ["object", "upload", "sign", @id, *parts],
                 file: file, filename: parts.last, content_type: content_type,
                 cache_control: cache_control, upsert: nil, metadata: ,
                 extra_headers: headers, query: { "token" => token })
end