# ファイル

```
POST   /storage/v1/bucket                    {"id":"avatars","public":true}
POST   /storage/v1/object/avatars/<名前>      本文: ファイルのバイト列
GET    /storage/v1/object/avatars/<名前>
DELETE /storage/v1/object/avatars/<名前>
```

## 公開バケットと非公開バケット

`public: true` のバケットのファイルは誰でもダウンロードでき、CDN がキャッシュします。
それ以外のバケットは、アップロードした本人だけがダウンロードでき、キャッシュされません。

プロフィール写真のようにすでに公開されているものは公開バケットに、それ以外は非公開が基本です。

Supabase 向けに書いたファイルのルールもそのまま使えます。`storage.foldername(name)`、`storage.filename(name)`、`storage.extension(name)` と `storage.buckets` の `name`・`owner` 列があるので、`(storage.foldername(name))[1] = auth.uid()::text` のような条件をコンソールの [アクセスルール] 画面、Supabase からの移行、または SQL エディタ・`run_sql`・マイグレーションの `create policy … on storage.objects` で入れると、このプロジェクトの名前に置き換わって動作します。SQL の場合、ストレージのテーブルはプラットフォームのものなので、残りの SQL の実行後に One Server がそのルールを作ります。

## S3 で使う

AWS SDK、aws CLI、rclone など S3 を使うツールから、同じバケットを扱えます。REST でアップロードしたファイルは S3 から見え、その逆も同じです。

```
endpoint:        https://<ref>.<zone>/storage/v1/s3
region:          ap-northeast-2
forcePathStyle:  true
```

アクセスキーは `create_s3_key` で作成し(シークレットアクセスキーはその応答にだけあります)、`list_s3_keys` で確認し、`revoke_s3_key` で失効させます。
アクセスキーはサービスロールなのでアクセスルール(RLS)を無視します。サーバーにだけ置いてください。

アプリのユーザーの権限で使うにはセッショントークン方式です。アクセスキー ID にプロジェクトの ref、シークレットアクセスキーに公開キー(`bw_publishable_…`)、セッショントークンにユーザーのアクセストークンを指定します。
そのユーザーのアクセスルールがそのまま適用されます。

ListBuckets、CreateBucket、DeleteBucket、HeadBucket、ListObjectsV2、GetObject(Range)、HeadObject、PutObject、CopyObject、DeleteObject(s)、マルチパートアップロードに対応しています。
バージョニング、ACL、タグ、ライフサイクルは NotImplemented を返します。

## Supabase からファイルを移す

Supabase Storage も S3 で開けるので、rclone ひとつでバケットごと移せます。
パスはそのままなので、テーブルに保存したファイルパス（`avatars/123.png`）は変えなくてかまいません。

1. 先にこちらで同じ名前のバケットを作ります（`create_bucket`）。公開・非公開も Supabase と同じにします。
2. Supabase ダッシュボードの Storage 設定で S3 アクセスキーを作り、こちらでは `create_s3_key` で作ります。
3. rclone の設定（`~/.config/rclone/rclone.conf`）に両方を書きます。

```
[supabase]
type = s3
provider = Other
endpoint = https://<supabase-ref>.supabase.co/storage/v1/s3
region = <Supabase プロジェクトのリージョン>
access_key_id = <Supabase のアクセスキー ID>
secret_access_key = <Supabase のシークレットアクセスキー>

[oneend]
type = s3
provider = Other
endpoint = https://<ref>.<zone>/storage/v1/s3
region = ap-northeast-2
access_key_id = <create_s3_key のアクセスキー ID>
secret_access_key = <create_s3_key のシークレットアクセスキー>
```

4. バケットごとにコピーします。もう一度実行すると変わったファイルだけ送ります。

```sh
rclone copy supabase:avatars oneend:avatars --progress
rclone check supabase:avatars oneend:avatars   # 抜けがないか確認
```

aws CLI しかない場合は、一度ダウンロードしてからアップロードします。

```sh
aws s3 sync s3://avatars ./avatars --endpoint-url https://<supabase-ref>.supabase.co/storage/v1/s3
aws s3 sync ./avatars s3://avatars --endpoint-url https://<ref>.<zone>/storage/v1/s3
```

1 ファイルの最大サイズはプランで決まります（無料 50MB、Pro 5GB）。公開アドレスは `https://<ref>.<zone>/storage/v1/object/public/<バケット>/<パス>` に変わるので、テーブルにアドレス全体を保存している場合はそこだけ直します。

## 再開可能なアップロード(TUS)

大きなファイルは TUS でアップロードすれば、接続が切れても続きから送れます。tus-js-client や Uppy をそのまま使えます。

```
endpoint:  https://<ref>.<zone>/storage/v1/upload/resumable
headers:   Authorization: Bearer <key or access token>, x-upsert: true
metadata:  bucketName, objectName, contentType, cacheControl
```

1 日のあいだ続きを受け取らなかったアップロードは期限切れになり、削除されます。
通常のアップロードでも S3 と TUS でも、ファイル 1 つの最大サイズはプランが決めます(無料 50MB、Pro 5GB)。バケットのサイズ制限のほうが小さければ、そちらに従います。

## ツールでファイルを扱う

```
list_objects        バケット内のフォルダーを表示 （prefix、search）
upload_object       ファイルを1つアップロード （2MBまで、バイナリは base64）
download_object     ファイルを1つダウンロード （2MBまで）
delete_object       ファイルを1つ削除
create_signed_url   非公開のファイルを決まった時間だけダウンロードできるアドレス （最大7日）
create_upload_url   大きなファイル（画像・動画）を PUT でアップロードするアドレス （2時間、1ファイル）
update_bucket       バケットの公開・非公開、ファイルサイズの上限、受け付ける形式を変更
empty_bucket        バケット内のファイルをすべて削除 （confirm にバケット名）
delete_bucket       空のバケットを削除 （confirm にバケット名）
```

もっと大きいファイルは上の `/storage/v1` のアドレスでアップロード、ダウンロードします。

手元の画像や動画を入れるときは、中身をツールの引数で送らず、`create_upload_url` でURLを受け取って
その `url` にファイルを PUT します: `curl -X PUT -H 'content-type: video/mp4' --data-binary @./intro.mp4 '<url>'`。
1回の PUT は `max_bytes`（プランのファイル1つの上限: 無料 50MB、Pro 5GB。バケットの上限がより小さければそれ）までです。遅い回線で大きなファイルは、途中から再開できるアップロード（TUS）が便利です。
REST では `POST /v1/projects/<ref>/buckets/<バケット>/upload-urls` です。

バケットを作るとき（`create_bucket`）か後から（`update_bucket`）、`file_size_limit`（例: `"5MB"`）と `allowed_mime_types`（例: `["image/*"]`）で受け付けるファイルを決めます。
バケットを削除するには、先に `empty_bucket` で空にし、`delete_bucket` の `confirm` にバケット名をそのまま入れます。`empty_bucket` も `confirm` にバケット名を受け取ります。
元に戻せないツールはすべて同じように、`confirm` に消すものの名前を受け取ります: `empty_bucket`、`delete_queue`、`purge_queue`、`reset_branch`、`delete_branch`、`remove_function`、`remove_domain`、`delete_gpu_server`、`disable_extension`、`remove_user`（メールアドレスまたは id）、`reset_database_password`・`set_spend_cap`（オフにするとき）・`rotate_signing_key`（`grace_hours: 0` のとき）はプロジェクト名です。違うか空なら、何を入れるべきかを示して拒否します。
REST では `PATCH /v1/projects/<ref>/buckets/<バケット>`、`POST /v1/projects/<ref>/buckets/<バケット>/empty`、`DELETE /v1/projects/<ref>/buckets/<バケット> {confirm}` です。

## ストレージの設定、以前のバージョン、デプロイに接続したバケット

```
get_storage_settings      ファイル1つの最大サイズ、画像変換、S3 アドレス、バケットごとのバージョン保存
set_storage_settings      プロジェクト全体のファイルサイズ上限と画像変換（省いた項目はそのまま）
set_s3_enabled            S3 アドレスのオン・オフ（キーは残ります）
set_bucket_versioning     バケットが上書き・削除したファイルを以前のバージョンとして残すか、何日残すか
list_object_versions      以前のバージョン一覧（name を渡すとそのファイルだけ）
restore_object_version    以前のバージョンを今のファイルに戻す
remove_object_version     以前のバージョンを完全に削除（confirm にファイル名）
list_bucket_connections   デプロイに接続したバケットと入れる環境変数
connect_bucket            バケット1つだけを開く S3 キーをデプロイに <接頭辞>_BUCKET などとして入れる
disconnect_bucket         接続のキーを無効にして変数を外す（confirm に接頭辞）
list_storage_policies     ファイルの表（objects）・バケットの表（buckets）のアクセスルール
create_storage_policy     コンソールのテンプレート（public-read、signed-in-read、own-folder など）か直接書いたルールを作る
remove_storage_policy     ルールを削除（confirm にルール名、既定のルールは削除できません）
```

ファイルの表のルールは run_sql では作れないので `create_storage_policy` を使います。条件式の `auth.uid()` は `uid()` に変わります。
production への接続とその解除はオーナーと管理者だけ、それ以外は開発者以上が実行できます。無料プランにはありません。

---

https://end.blackall.ai/docs/storage?lang=ja
