Skip to content

Add media usage index foundation#1670

Closed
khoinguyenpham04 wants to merge 9 commits into
mainfrom
feature/media-usage-index-foundation
Closed

Add media usage index foundation#1670
khoinguyenpham04 wants to merge 9 commits into
mainfrom
feature/media-usage-index-foundation

Conversation

@khoinguyenpham04

@khoinguyenpham04 khoinguyenpham04 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds the internal media usage index foundation for content entries.

This is the first implementation layer for Media Library maturity work discussed in #1655. It gives EmDash a durable, provider-aware record of where media assets are referenced by content, without exposing that data through a public API or UI yet.

The new index tracks usage for content fields that can hold media references, including top-level image/file fields, repeater image subfields, Portable Text image blocks, and structured provider media references. Local media is indexed by media_id, while non-local structured references are indexed by provider and provider asset ID so future integrations like Cloudflare Images, Mux, or Cloudinary do not require redesigning the storage model.

The migration adds two internal tables:

  • _emdash_media_usage_sources
  • _emdash_media_usage

The source/generation model makes usage replacement safe for D1-style environments by avoiding a visible delete-then-insert gap when reindexing a content item.

The index is maintained across the content lifecycle:

  • create, update, duplicate, soft delete, restore, permanent delete
  • schedule, unschedule, publish, unpublish, discard draft
  • revision restore and draft revision flows
  • plugin content writes
  • seed content writes
  • schema changes that add, remove, or change media-bearing fields
  • migration backfill for existing content when the usage tables are introduced

This PR intentionally does not add:

  • public usage API endpoints
  • admin UI
  • usage counts in media list responses
  • safe-delete enforcement
  • replace-in-place workflows

Those are follow-up features built on top of this foundation.

Discussion: #1655

Closes: n/a

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: OpenCode, GPT-5.5

Screenshots / test output

No screenshots. This PR does not add UI.

Verified locally:

pnpm lint
pnpm typecheck
pnpm format
pnpm --filter emdash exec vitest run tests/unit/media/usage-extractor.test.ts tests/integration/database/media-usage-index.test.ts tests/integration/database/media-usage-repository.test.ts tests/integration/content/media-usage-index.test.ts tests/integration/database/migrations.test.ts tests/integration/seed-live-revisions.test.ts tests/unit/seed/apply.test.ts tests/unit/seed/media.test.ts

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 30, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
emdash-demo-cache aeb745a Jun 30 2026, 05:59 PM

@changeset-bot

changeset-bot Bot commented Jun 30, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: aeb745a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 16 packages
Name Type
emdash Minor
@emdash-cms/cloudflare Minor
@emdash-cms/sandbox-workerd Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/do-demo-site Patch
@emdash-cms/do-solo-demo-site Patch
@emdash-cms/admin Minor
@emdash-cms/auth Minor
@emdash-cms/blocks Minor
@emdash-cms/gutenberg-to-portable-text Minor
@emdash-cms/x402 Minor
create-emdash Minor
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 30, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
emdash-playground aeb745a Jun 30 2026, 05:59 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 30, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
emdash-demo-do aeb745a Jun 30 2026, 05:58 PM

@github-actions github-actions Bot added review/needs-review No maintainer or bot review yet area/core size/XL labels Jun 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Scope check

This PR changes 2,417 lines across 19 files. Large PRs are harder to review and more likely to be closed without review.

If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs.

See CONTRIBUTING.md for contribution guidelines.

@pkg-pr-new

pkg-pr-new Bot commented Jun 30, 2026

Copy link
Copy Markdown

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@1670

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@1670

@emdash-cms/auth-atproto

npm i https://pkg.pr.new/@emdash-cms/auth-atproto@1670

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@1670

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@1670

@emdash-cms/contentful-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/contentful-to-portable-text@1670

emdash

npm i https://pkg.pr.new/emdash@1670

create-emdash

npm i https://pkg.pr.new/create-emdash@1670

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@1670

@emdash-cms/plugin-cli

npm i https://pkg.pr.new/@emdash-cms/plugin-cli@1670

@emdash-cms/plugin-types

npm i https://pkg.pr.new/@emdash-cms/plugin-types@1670

@emdash-cms/registry-client

npm i https://pkg.pr.new/@emdash-cms/registry-client@1670

@emdash-cms/registry-lexicons

npm i https://pkg.pr.new/@emdash-cms/registry-lexicons@1670

@emdash-cms/sandbox-workerd

npm i https://pkg.pr.new/@emdash-cms/sandbox-workerd@1670

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@1670

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@1670

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@1670

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@1670

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@1670

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@1670

@emdash-cms/plugin-field-kit

npm i https://pkg.pr.new/@emdash-cms/plugin-field-kit@1670

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@1670

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@1670

commit: aeb745a

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds the internal “media usage index” foundation to track where media is referenced across content entries (including provider-aware assets), enabling future features like usage views and safer delete workflows.

Changes:

  • Introduces _emdash_media_usage_sources and _emdash_media_usage tables with a backfilling migration (046_media_usage_index).
  • Adds extraction + indexing helpers and a repository for replacing/querying current usage generations.
  • Wires media-usage maintenance into key write paths (content lifecycle handlers, schema changes, plugin writes, seed writes, and revision/draft flows), with comprehensive unit/integration coverage.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/core/tests/unit/media/usage-extractor.test.ts Unit coverage for media reference extraction across supported field shapes.
packages/core/tests/integration/database/migrations.test.ts Registers migration 046 in the integration migration test list.
packages/core/tests/integration/database/media-usage-repository.test.ts Integration tests for MediaUsageRepository replace/query semantics and D1 bind-limit batching.
packages/core/tests/integration/database/media-usage-index.test.ts Integration tests for schema/index creation, down/up behavior, and migration backfill.
packages/core/tests/integration/content/media-usage-index.test.ts End-to-end integration coverage across content lifecycle operations and indexing behavior.
packages/core/src/seed/apply.ts Ensures seed create/update writes also maintain media usage sources for the correct live/draft state.
packages/core/src/schema/registry.ts Hooks schema mutations (field create/update/delete, collection delete) to reindex or clear usage as needed.
packages/core/src/plugins/context.ts Updates plugin write/delete paths to refresh usage metadata (including deleted_at) for affected content.
packages/core/src/media/usage-index.ts New indexing orchestration: computes indexed fields and replaces content/collection usage sources.
packages/core/src/media/usage-extractor.ts New extractor that walks field data and portable text to produce normalized usage references.
packages/core/src/media/mime.ts Adds MediaKind classification helper derived from MIME types.
packages/core/src/emdash-runtime.ts Ensures draft revision save/restore paths also update media usage for draft state.
packages/core/src/database/types.ts Adds DB typings for the new media usage tables.
packages/core/src/database/repositories/media-usage.ts New repository implementing generation-based replace + current-usage queries.
packages/core/src/database/migrations/runner.ts Registers migration 046 in the static migration provider.
packages/core/src/database/migrations/046_media_usage_index.ts Creates usage tables + indexes and backfills existing content usage.
packages/core/src/api/handlers/revision.ts Refreshes media usage when restoring a revision via the API handler.
packages/core/src/api/handlers/content.ts Integrates media usage maintenance across content CRUD/publish/schedule/revision transitions and i18n syncing.
.changeset/media-usage-index.md Minor release notes for introducing internal media usage tracking foundation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/core/src/media/usage-extractor.ts
Comment on lines +127 to 133
await replaceContentMediaUsage(
trx,
revision.collection,
updated,
updated.status === "published" ? "live" : "draft",
);

Comment on lines +69 to +76
const tableName = `ec_${collection}`;
const result = await sql<Record<string, unknown>>`
SELECT * FROM ${sql.ref(tableName)}
`.execute(db);
const revisionRepo = new RevisionRepository(db);

for (const row of result.rows) {
const item = rowToContentItem(collection, row);
@github-actions github-actions Bot added review/needs-rereview Author pushed changes since the last review and removed review/needs-review No maintainer or bot review yet labels Jun 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Overlapping PRs

This PR modifies files that are also changed by other open PRs:

This may cause merge conflicts or duplicated work. A maintainer will coordinate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core overlap review/needs-rereview Author pushed changes since the last review size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants