import { createSidecarProxy } from '@@/sidecar/create-proxy'; import { mountPrefix } from '@@/plugins/manifest'; import { manifest } from '../manifest'; // /api/photos/* — auth, then forward to officer-photos. No routes of its own and no Immich knowledge: // this file must never grow app logic. The sidecar owns the Immich contract and holds its API key. // // ── The prefix is DERIVED, not written ── // // It was the literal '/api/photos', which is right only by coincidence: `mountPrefix` returns `/photos` // for a first-party publisher, and the proxy strips exactly `prefix.length` characters to build the // sidecar's path. Published by anyone else this mounts at `/api/p//photos` and a literal would // forward `/alice/photos/assets` to a sidecar expecting `/assets`. Same reasoning, and the same fix, as // `plugins/music/api/router.ts`. const proxy = createSidecarProxy({ name: 'photos', prefix: `/api${mountPrefix({ appName: 'photos', manifest })}`, // Originals and `download/archive` zips are large and Immich builds the archive as it streams it, so the // socket can sit quiet longer than the default 60s idle drop allows. timeoutSeconds: 600, // Immich judges an asset from its first few KB and rejects immediately, while we are still writing — // and the response is lost in the teardown, which is what made every large upload fail with an // unexplained empty 400. Buffering here removes the overlap. The sidecar does the same on its own hop // to Immich (sidecar/routes.ts → readBodyCapped), and both are needed: fixing one alone still lost the // answer roughly two runs in three at 32 MB. bufferRequestBody: true, }); export const router = proxy.router;