Skip to content

PR プレビュー (uzu preview) ​

内部ドキュメント

このドキュメントは内部実装の詳細です。ゲーム開発者向けの情報は docs.code.uzu-app.com を参照してください。

シナリオ repo の PR を、差分ではなく実物で確認するための仕組み。 uzu preview はビルドしたゲームを R2 に 1 本置き、emulator の起動 URL を返す。 revision は作らないので、配信中のシナリオには一切影響しない。

使い方 ​

bash
uzu preview                      # emulator の URL を出力する
uzu preview --json               # { "id", "url", "expiresAt" } を stdout へ
uzu preview --label "PR #453"    # backend の監査ログに残す表示名

--json のときは進捗もビルドツールの出力も stderr へ寄せるので、stdout をそのまま JSON として読める。CI では UZU_PUBLISH_TOKEN で認証する (uzu publish と同じ)。

--label は 200 バイト以内・改行なし。ビルドの前に検証するので、長すぎる PR タイトルを そのまま渡してもビルドが無駄にならない。

仕組み ​

uzu preview
  → ビルド → upload session を preview モードで取得 (id = "pv-" + ULID)
  → data.zip / files/* / logic.js を R2 へ
  → registerRevision は呼ばない
  → 応答の署名済み endpoint から emulator の URL を組んで出力
  → 14 日後に R2 のライフサイクルが実体を消す → リンクは 404 になる

publish との違いは「revision を登録するか」だけで、ビルドからアップロードまでは 同じ経路 (bundle-upload.ts) を通る。

publishpreview
revisionIdULIDpv- + ULID
scenario_revisions作る作らない (backend が 403)
配信 endpoint の署名24 時間15 日
実体の寿命無期限R2 のライフサイクルで 14 日
キャラクター画像 (icon / playCard)Cloudflare Images へアップロードアップロードしない

署名を実体より長い 15 日にしているのは、常に「実体が先に消える」向きへ倒すため。 逆にすると、ファイルはあるのにリンクだけ死んでいる窓ができる。

pv- プレフィックスが担っていること ​

pv- は 3 か所で同じ意味を持つ。片方だけ変えると壊れる。

  1. R2 のライフサイクル規則が、この prefix を見て 14 日で削除する
  2. POST /uzu_code/scenario_revisions が、この prefix の upload token を 403 で弾く (実体が消える前提のものを配信レコードにしない)
  3. orphan prefix の掃除を実装するときは、この prefix を対象外にする (プレビューは対応する revision を持たないので、そのままだと発行直後に消える)

運用要件 ​

R2 バケット uzu-code-revisions に、prefix pv- を 14 日で削除するライフサイクル規則が必要。 規則が無いとプレビューの実体が無期限に残る (リンクは 15 日で開けなくなるが、オブジェクトは残る)。

認可 ​

プレビューの URL を知っていれば誰でも部屋に入れる。play-server の WebSocket は seatId しか見ておらず、revisionId の推測不可能性がそのままアクセス制御になっている。 pv-{scenario}-pr{N} のような決め打ちの ID にすると PR 番号を当てるだけで未公開シナリオの state を読めてしまうため、ULID のまま扱う。