JA
ベータ版の翻訳

@core / media

1.1.0 ▾
認証済みMIT
GitHub

メディアライブラリ:署名付き直接アップロード、実ファイル形式の検証、EXIF/GPS 除去、代替テキスト、焦点、srcset

コード13 ファイルコンテキスト約 777 トークンスキャン合格

.genpmignore 適用後に組み込まれる正確なツリーです。固定先:

src/lib/media/AGENTS.md読み取り専用 · 868490c
# @core/media — rules for AI agents

## Purpose
Media library on top of @core/storage: the browser uploads directly with a signed URL to a private staging key
(`uploads/pending/<id>.<ext>`), then `confirmUpload` checks the real file type by its bytes (declared type must match),
removes EXIF/GPS/XMP from JPEG, PNG and WebP without re-encoding, writes the validated bytes to the final `public/`
key, deletes the staging copy and stores dimensions. Malformed images (chunk lengths past the end) are rejected. Alt text and focal point per file, responsive URLs (Cloudflare Images or Next.js
image optimizer) and ready `<img>` attributes. SVG and HTML are never accepted. Table: `media`.

## Map
- `index.ts` — public API: `createUpload`, `confirmUpload`, `getMedia`, `updateMedia`, `deleteMedia`, `imageUrl`, `imgAttrs`, `mediaAdminResource`.
- `remote.ts` — `importRemoteImage(url, { allowedHosts })` for server-side imports (https, host allowlist, size limit).
- `library.ts` — upload flow, allowed types and `stagingKey(media)`. `sniff.ts`, `strip.ts` — byte checks. `urls.ts` — URLs and `<img>` attributes.
- `adapters/hono.ts` — `mediaRoutes({ authorize })`. `adapters/next.ts` — `createUploadRoute`, `confirmUploadRoute`.

## Integration
1. Configure @core/storage first (bucket CORS must allow `PUT` from the site). Recommended: a bucket lifecycle rule
   that deletes `uploads/pending/` objects after 1 day (abandoned or replayed uploads). Optional `MEDIA_TRANSFORM`:
   `cloudflare` (Images transformations enabled on the zone), `vercel` (Next.js image optimizer; add the storage host to `images.remotePatterns`) or `none`.
2. Migrations as in `src/lib/db/AGENTS.md`.
3. Mount the upload routes with an `authorize(req)` that returns `{ userId }` only for users with `media:create` (@core/rbac).
4. Upload from the browser: `POST /api/media/uploads` with `{ filename, mime, size }` → `PUT` the file to `upload.url`
   with `upload.headers` → `POST /api/media/uploads/<id>/confirm`. Store the media `id` in your content.
5. Render: `const m = await getMedia(id); <img {...imgAttrs(m, { sizes: '(min-width: 768px) 50vw, 100vw' })} />`.
6. Add `mediaAdminResource` to `src/genpm/admin.ts`.
7. Verify: upload a photo with GPS data; after confirm, the stored file has no EXIF and the row has width/height.

## Conventions
- Reference media by `id` in content; resolve URLs at render time (driver or CDN can change).
- Every non-decorative image needs `alt`; the admin can filter `missingAlt=true`.
- Hero/LCP images: `imgAttrs(m, { priority: true })`; everything else stays lazy.

## Don't
- Don't accept files without `confirmUpload`; pending or rejected media must never be shown.
- Don't presign uploads to the final `public/` key: a signed PUT can be replayed until it expires and would swap a
  validated file for an unchecked one (served `immutable`). Upload to `stagingKey()`; only `confirmUpload` writes `public/`.
- Don't allow SVG uploads or serve user files from the site's own origin without the storage route's sandbox headers.
- Don't hotlink third-party images; copy them into storage first.

@core/media を報告

パッケージを報告するには GitHub でログインしてください。

GitHub で続ける