Skip to content

refactor(api): move transfer artifacts into oRPC - #669

Merged
hmjn023 merged 5 commits into
developfrom
codex/refactor/orpc-remove-rest-routes
Aug 12, 2026
Merged

refactor(api): move transfer artifacts into oRPC#669
hmjn023 merged 5 commits into
developfrom
codex/refactor/orpc-remove-rest-routes

Conversation

@hmjn023

@hmjn023 hmjn023 commented Aug 12, 2026

Copy link
Copy Markdown
Owner

概要

旧RESTのsource transfer routeとjob artifact routeを削除し、転送処理をoRPCへ統合します。

変更内容

  • source dump/importをoRPC経由へ統一
  • job artifact downloadをReadableStreamのoRPC procedureへ移行
  • V2 Jobs画面をoRPC streamからBlobを生成する方式へ変更
  • obsoleteなAPI endpoint定義と旧routeを削除

検証

  • git diff --check: 成功
  • typecheck/lint: worktreeの依存未復元により実行不可
  • OpenAPI再生成: @orpc/openapi未解決により実行不可

Summary by CodeRabbit

  • 新機能
    • ジョブ画面から生成された成果物を直接ダウンロードできるようになりました。
    • ダウンロード中の状態表示と、失敗時のエラー通知に対応しました。
  • 改善
    • メディアソースのエクスポート・インポート処理をジョブ方式に統一し、処理完了まで安全に確認できるようになりました。
    • 旧式の専用ダウンロード・インポート経路を整理しました。

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@hmjn023, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 46 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 60480a2b-9160-4375-9956-95ab00c8ae25

📥 Commits

Reviewing files that changed from the base of the PR and between 39aed4a and a3a2e7e.

📒 Files selected for processing (11)
  • apps/server/public/openapi.json
  • apps/server/scripts/generate-swagger-spec.ts
  • apps/server/src/infrastructure/api-clients/sources-api.ts
  • apps/server/src/infrastructure/api/routers/jobs-router.ts
  • apps/server/src/routes/v2/jobs.tsx
  • apps/server/src/tests/unit/infrastructure/api-clients/sources-api-ext.test.ts
  • apps/tauri/src/infrastructure/api-clients/sources-api.ts
  • packages/client/src/index.ts
  • packages/client/src/job-artifact.ts
  • packages/core/src/domain/contract/jobs.contract.ts
  • packages/ui/src/screens/v2-jobs-screen.tsx
📝 Walkthrough

Walkthrough

メディアソースのエクスポートとインポートをoRPCベースのジョブ処理へ移行しました。成果物取得用のサーバーAPIと、ジョブ画面からのBlobダウンロード処理を追加しました。旧HTTPルートを削除しました。

Changes

ソースAPIと成果物取得

Layer / File(s) Summary
成果物ダウンロード契約とサーバー実装
packages/core/src/domain/contract/jobs.contract.ts, packages/core/src/domain/jobs/schemas.ts, apps/server/src/infrastructure/api/routers/jobs-router.ts, apps/server/src/routes/api/jobs.$jobId.artifact.ts, apps/server/src/infrastructure/api-clients/shared/endpoints.ts
jobsContract.downloadArtifactを追加しました。artifact.downloadUrlを削除しました。サーバーはジョブ状態、成果物パス、有効期限、ファイル種別を検証してストリームを返します。旧成果物ルートとエンドポイント定義を削除しました。
ソースAPIのジョブ処理移行
apps/server/src/infrastructure/api-clients/sources-api.ts, apps/tauri/src/infrastructure/api-clients/sources-api.ts, apps/server/src/routes/api/sources.$mediaSourceId.dump.ts, apps/server/src/routes/api/sources.$mediaSourceId.import.ts, apps/server/src/routes/api/sources.$mediaSourceId.import-lancedb.ts, apps/server/src/tests/unit/infrastructure/api-clients/sources-api-ext.test.ts
エクスポートをジョブ登録、完了待機、成果物取得の処理へ変更しました。ZIPとLanceDBのインポートをoRPC呼び出しへ変更しました。旧HTTPルートとテスト用の直接fetch処理を削除しました。
ジョブ画面のダウンロード連携
apps/server/src/routes/v2/jobs.tsx, packages/ui/src/screens/v2-jobs-screen.tsx
成果物をBlobへ変換してダウンロードする処理を追加しました。ダウンロード中はボタンを無効化し、状態を表示します。取得または保存に失敗した場合はエラートーストを表示します。

Estimated code review effort: 3 (Moderate) | ~25 minutes

Mergeability Score: 🟠 High · up to 39aed

The change moves source exports and job artifact downloads to a new transfer path while removing the legacy routes. As implemented, users may be able to retrieve another user's artifact if they know its job ID, and stalled exports may never finish; the PR is not merge-ready until authorization and bounded cancellation or timeout behavior are addressed.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant V2JobsScreen
  participant jobsRouter
  participant ArtifactFile
  User->>V2JobsScreen: 成果物のダウンロードを選択
  V2JobsScreen->>jobsRouter: downloadArtifact(jobId)
  jobsRouter->>ArtifactFile: ファイルを検証して読み取る
  ArtifactFile-->>jobsRouter: ReadableStream
  jobsRouter-->>V2JobsScreen: 成果物ストリーム
  V2JobsScreen-->>User: Blobとして保存
Loading

Possibly related PRs

  • hmjn023/solid-imager#663: jobs-router.tsjobs.contract.tsv2-jobs-screen.tsxのジョブ基盤に関連し、本変更はその基盤へ成果物ダウンロードを追加しています。
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed タイトルは、レガシーな転送処理をoRPCへ移行するという変更の主目的を正確かつ簡潔に示しています。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/refactor/orpc-remove-rest-routes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (3)
apps/server/src/tests/unit/infrastructure/api-clients/sources-api-ext.test.ts (1)

28-80: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

ポーリングとエラー経路のテストが不足しています。

jobs.getmockResolvedValueで常にcompletedを返します。そのためwaitForExportのループ、失敗、キャンセル、および成果物欠落の分岐が検証されません。以下のケースを追加してください。

  • jobs.getpendingcompleted を返す遷移(mockResolvedValueOnceを使用)。
  • status: "failed" で例外が送出されること。
  • artifact: null"Export completed without an artifact" が送出されること。

waitForExportの待機は500msです。テストではvi.useFakeTimers()を使ってください。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/server/src/tests/unit/infrastructure/api-clients/sources-api-ext.test.ts`
around lines 28 - 80, Expand the tests around fetchSourceDump and waitForExport
to cover polling and error paths: use vi.useFakeTimers() and mock jobs.get with
mockResolvedValueOnce to transition from pending to completed, advance timers so
the poll resolves, and assert the download succeeds. Add cases asserting status
"failed" rejects and completed with artifact: null rejects with "Export
completed without an artifact"; restore real timers after each test.
apps/server/src/infrastructure/api/routers/jobs-router.ts (1)

155-170: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

statcreateReadStream は同じファイル記述子を共有していません。

現在の実装はfs.statでパスを検査し、その後createReadStreamで同じパスを再度開きます。検査と使用の間にパスが差し替えられる可能性が残ります。JobTransferDirectoryはサーバ管理下なので実害は限定的です。厳密にしたい場合はfs.openでハンドルを取得し、fstatcreateReadStream({ fd })を同じハンドルで使ってください。

また、oRPCが返却ストリームを消費しない経路(出力検証エラーや接続断)では、ファイル記述子が解放されない可能性があります。ストリームのエラーとキャンセルを監視してdestroyすることを検討してください。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/infrastructure/api/routers/jobs-router.ts` around lines 155 -
170, Update the artifact handling around the jobs-router return path to open the
file once with fs.open, validate it with fstat, and pass the same handle to
createReadStream instead of re-opening the path. Preserve the existing NOT_FOUND
behavior for missing or non-file artifacts. Ensure the returned stream releases
the file descriptor on stream errors, cancellation, or other early termination
paths.
packages/ui/src/screens/v2-jobs-screen.tsx (1)

396-409: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

共有 Button コンポーネントの使用を検討してください。

同じコンポーネント内のcancelretryのアクションはButton(422行、441行)を使います。新しいダウンロード操作は生の<button>にクラスを直接指定しています。スタイルの一貫性が失われます。

DESIGN.mdを確認し、bun run design:lintで結果を検証してください。

パスの指示に「Before implementing UI, consult DESIGN.md and validate the result with bun run design:lint」があります。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/screens/v2-jobs-screen.tsx` around lines 396 - 409, Replace
the raw button in the download action with the shared Button component, matching
the existing cancel and retry actions in the same component while preserving the
current download behavior, disabled state, busy state, label, icon, and styling
intent. Consult DESIGN.md before implementing and validate the result with bun
run design:lint.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/server/src/infrastructure/api-clients/sources-api.ts`:
- Around line 14-25:
共有パッケージにoRPCクライアントを引数として受け取るエクスポート用ポーリング・ダウンロードヘルパーを抽出し、タイムアウトとBlobのMIMEタイプ処理も一元化してください。apps/server/src/infrastructure/api-clients/sources-api.tsのwaitForExport(14-25行)は共有ヘルパーへ移し、apps/tauri/src/infrastructure/api-clients/sources-api.tsのwaitForExport(13-24行)は削除してclientを渡して共有ヘルパーを呼び出すよう更新してください。
- Around line 14-25: Update waitForExport to support a bounded wait, using a
timeout and/or AbortSignal so polling cannot continue indefinitely when a job
remains pending or in_progress. Check the timeout or cancellation between polls
and terminate with an appropriate error while preserving the existing completed,
failed, and cancelled handling; use exponential backoff if consistent with the
surrounding API-client conventions.

Apply the same fix in `@apps/tauri/src/infrastructure/api-clients/sources-api.ts`
around lines 13 - 24: 同じ無期限ポーリングがデスクトップ側にも存在します。
- Around line 120-124: Update the artifact download flow around the `new
Response(stream).blob()` call to preserve the MIME type from
`completedJob.artifact.contentType`. Construct the returned Blob with the
downloaded stream data and that content type so its `type` matches the completed
artifact metadata.

Apply the same fix in `@apps/tauri/src/infrastructure/api-clients/sources-api.ts`
around lines 34 - 38: 同じ MIME タイプ欠落がデスクトップ側にも存在します。

In `@apps/server/src/infrastructure/api/routers/jobs-router.ts`:
- Around line 131-147: downloadArtifact
のハンドラーに既存の認証ミドルウェアを適用し、認証済みユーザーだけが実行できるようにしてください。取得した job
の所有者がリクエストの認証ユーザーと一致することを、成果物を返す前に検証し、不一致時は NOT_FOUND
または既存の認可エラーを返してください。appRouter の直接処理経路でも認証コンテキストが利用されるよう、関連するルート設定を更新してください。

In `@apps/server/src/routes/v2/jobs.tsx`:
- Around line 69-79: Update the download flow around anchor.click() to defer
URL.revokeObjectURL(url) to the next task, ensuring the browser can start the
download before cleanup. Avoid the unnecessary Blob copy by applying
job.artifact.contentType through the Response headers when creating the blob,
and use that blob directly for the object URL.

In `@packages/core/src/domain/contract/jobs.contract.ts`:
- Around line 14-16: Update the downloadArtifact contract in jobs.contract.ts so
its OpenAPI representation defines an application/octet-stream response without
relying on z.instanceof(ReadableStream), while preserving RPC support for the
returned stream. Regenerate apps/server/public/openapi.json by running bun run
gen:spec and verify /jobs/downloadArtifact is included.

In `@packages/ui/src/screens/v2-jobs-screen.tsx`:
- Around line 243-252: Update the download function to add a catch block around
props.onDownload(job), matching the exception-swallowing behavior used by retry
and cancel, while preserving the existing finally block that resets
isDownloading.

---

Nitpick comments:
In `@apps/server/src/infrastructure/api/routers/jobs-router.ts`:
- Around line 155-170: Update the artifact handling around the jobs-router
return path to open the file once with fs.open, validate it with fstat, and pass
the same handle to createReadStream instead of re-opening the path. Preserve the
existing NOT_FOUND behavior for missing or non-file artifacts. Ensure the
returned stream releases the file descriptor on stream errors, cancellation, or
other early termination paths.

In
`@apps/server/src/tests/unit/infrastructure/api-clients/sources-api-ext.test.ts`:
- Around line 28-80: Expand the tests around fetchSourceDump and waitForExport
to cover polling and error paths: use vi.useFakeTimers() and mock jobs.get with
mockResolvedValueOnce to transition from pending to completed, advance timers so
the poll resolves, and assert the download succeeds. Add cases asserting status
"failed" rejects and completed with artifact: null rejects with "Export
completed without an artifact"; restore real timers after each test.

In `@packages/ui/src/screens/v2-jobs-screen.tsx`:
- Around line 396-409: Replace the raw button in the download action with the
shared Button component, matching the existing cancel and retry actions in the
same component while preserving the current download behavior, disabled state,
busy state, label, icon, and styling intent. Consult DESIGN.md before
implementing and validate the result with bun run design:lint.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4eb504d6-9bd8-4200-ac33-b94384791eb1

📥 Commits

Reviewing files that changed from the base of the PR and between ea8d3c3 and 39aed4a.

📒 Files selected for processing (13)
  • apps/server/src/infrastructure/api-clients/shared/endpoints.ts
  • apps/server/src/infrastructure/api-clients/sources-api.ts
  • apps/server/src/infrastructure/api/routers/jobs-router.ts
  • apps/server/src/routes/api/jobs.$jobId.artifact.ts
  • apps/server/src/routes/api/sources.$mediaSourceId.dump.ts
  • apps/server/src/routes/api/sources.$mediaSourceId.import-lancedb.ts
  • apps/server/src/routes/api/sources.$mediaSourceId.import.ts
  • apps/server/src/routes/v2/jobs.tsx
  • apps/server/src/tests/unit/infrastructure/api-clients/sources-api-ext.test.ts
  • apps/tauri/src/infrastructure/api-clients/sources-api.ts
  • packages/core/src/domain/contract/jobs.contract.ts
  • packages/core/src/domain/jobs/schemas.ts
  • packages/ui/src/screens/v2-jobs-screen.tsx
💤 Files with no reviewable changes (6)
  • apps/server/src/routes/api/jobs.$jobId.artifact.ts
  • apps/server/src/routes/api/sources.$mediaSourceId.import.ts
  • packages/core/src/domain/jobs/schemas.ts
  • apps/server/src/infrastructure/api-clients/shared/endpoints.ts
  • apps/server/src/routes/api/sources.$mediaSourceId.dump.ts
  • apps/server/src/routes/api/sources.$mediaSourceId.import-lancedb.ts

Comment thread apps/server/src/infrastructure/api-clients/sources-api.ts Outdated
Comment thread apps/server/src/infrastructure/api-clients/sources-api.ts Outdated
Comment thread apps/server/src/infrastructure/api/routers/jobs-router.ts
Comment thread apps/server/src/routes/v2/jobs.tsx Outdated
Comment thread packages/core/src/domain/contract/jobs.contract.ts Outdated
Comment thread packages/ui/src/screens/v2-jobs-screen.tsx
@hmjn023
hmjn023 merged commit 3bd421c into develop Aug 12, 2026
1 check passed
@hmjn023
hmjn023 deleted the codex/refactor/orpc-remove-rest-routes branch August 12, 2026 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant