Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
55a00f5
fix: use shared button in GPU view modal
Producdevity Jun 4, 2026
f3559e6
feat: add comment submit shortcut
Producdevity Jun 4, 2026
1edb2cd
fix: use pagination helper in SoCs router
Producdevity Jun 4, 2026
ad5ef7f
fix: type SoCs pagination input
Producdevity Jun 4, 2026
678be0d
fix: route comment shortcut through submit
Producdevity Jun 4, 2026
aa8f051
Merge pull request #420 from Producdevity/fix/gpu-view-modal-button
Producdevity Jun 4, 2026
68848ab
Merge pull request #422 from Producdevity/feat/comment-submit-shortcut
Producdevity Jun 4, 2026
be07efc
feat: lazy load language detection
Producdevity Jun 4, 2026
c7d63c7
refactor: move SoCs pagination into repository
Producdevity Jun 4, 2026
a045f90
test: cover SoCs pagination behavior
Producdevity Jun 4, 2026
e4363bc
fix: harden deferred language detection
Producdevity Jun 4, 2026
e2cca97
Merge pull request #423 from Producdevity/feat/franc-min-language-det…
Producdevity Jun 4, 2026
2d03d98
test: fix SoCs repository mocks
Producdevity Jun 4, 2026
192f004
chore: remove unused Stop Killing Games popup
Producdevity Jun 4, 2026
c418791
chore: remove unused SEO verification tags
Producdevity Jun 4, 2026
b1b6c81
refactor: standardize admin page layouts
Producdevity Jun 4, 2026
dc2b782
Merge pull request #425 from Producdevity/fix/remove-unused-seo-verif…
Producdevity Jun 4, 2026
8c8d8b9
test: satisfy Prisma client constructor type
Producdevity Jun 4, 2026
a2c508a
chore: remove unused beta warning popup
Producdevity Jun 4, 2026
36260ab
fix: constrain listing cover layout
Producdevity Jun 4, 2026
5d871a3
fix: restore custom field template search
Producdevity Jun 4, 2026
cd4e914
chore: use cache duration constants
Producdevity Jun 4, 2026
9f68bb6
Merge pull request #424 from Producdevity/fix/remove-stop-killing-gam…
Producdevity Jun 4, 2026
0565509
Merge pull request #421 from Producdevity/fix/socs-pagination-helper
Producdevity Jun 4, 2026
a80d4c7
refactor: use admin error state for trust logs
Producdevity Jun 4, 2026
9adfe3d
chore: use semantic cache duration buckets
Producdevity Jun 4, 2026
33f9555
fix: use report terminology for CPU admin page
Producdevity Jun 4, 2026
688592c
test custom field template field-name search
Producdevity Jun 4, 2026
dd0d7d1
align tgdb platforms cache ttl
Producdevity Jun 4, 2026
0c32abc
centralize refetch intervals
Producdevity Jun 4, 2026
692466a
align short duration bucket
Producdevity Jun 4, 2026
4680a93
refactor: use shared admin stats for trust logs
Producdevity Jun 4, 2026
ac117c1
fix: restore admin stats fallback
Producdevity Jun 4, 2026
30b57c8
Merge pull request #429 from Producdevity/chore/cache-duration-constants
Producdevity Jun 4, 2026
40e59d7
Merge pull request #427 from Producdevity/fix/listing-cover-layout
Producdevity Jun 4, 2026
5fbfa79
refactor admin empty states
Producdevity Jun 4, 2026
f923851
Merge pull request #426 from Producdevity/refactor/admin-page-layout-…
Producdevity Jun 4, 2026
426dd14
chore: address admin profile ui todos
Producdevity Jun 4, 2026
decbc27
Merge staging into custom field template search
Producdevity Jun 4, 2026
282d054
Address admin empty-state review comments
Producdevity Jun 4, 2026
c0cdca3
Merge pull request #428 from Producdevity/fix/custom-field-template-s…
Producdevity Jun 4, 2026
3e90539
Refine admin profile PR feedback
Producdevity Jun 4, 2026
6856de9
Throw on duplicate performance scale replacement
Producdevity Jun 5, 2026
b1ff876
Filter admin CPU and GPU brands server-side
Producdevity Jun 5, 2026
1c6dfdc
Merge pull request #431 from Producdevity/chore/admin-profile-ui-impr…
Producdevity Jun 5, 2026
a10d82f
Delegate mobile brand queries to repository
Producdevity Jun 5, 2026
f14080d
Keep mobile brand queries bounded
Producdevity Jun 5, 2026
7abf8b0
build: update pnpm version to 11.5.2
Producdevity Jun 5, 2026
ba375bb
Avoid unnecessary filter destructuring
Producdevity Jun 5, 2026
af46a87
refactor: resolve code quality TODOs
Producdevity Jun 5, 2026
32bc3e4
fix: align GameNative startup default
Producdevity Jun 5, 2026
79ac32c
reduce notification polling
Producdevity Jun 5, 2026
5b70a20
Merge pull request #432 from Producdevity/fix/admin-brand-filtering
Producdevity Jun 5, 2026
b945858
clean notification files
Producdevity Jun 5, 2026
74dab00
Address code quality PR feedback
Producdevity Jun 5, 2026
d3b4060
Merge branch 'staging' of github.com:Producdevity/EmuReady into refac…
Producdevity Jun 5, 2026
a91d31c
Track session metrics accurately
Producdevity Jun 5, 2026
f40a287
fix static image type resolution
Producdevity Jun 5, 2026
ae54834
Merge pull request #434 from Producdevity/fix/gamenative-startup-default
Producdevity Jun 5, 2026
800e3da
Gate image provider switching to moderators
Producdevity Jun 5, 2026
8bbfcee
clean notification batching helpers
Producdevity Jun 5, 2026
fa7e7af
remove unused notification types
Producdevity Jun 5, 2026
050f8a0
use notification delivery enums
Producdevity Jun 5, 2026
10e3275
Cover session tracker privacy and fallback paths
Producdevity Jun 5, 2026
2c9058a
Avoid stale session page load times
Producdevity Jun 5, 2026
cc06b84
Keep IGDB provider moderator-only
Producdevity Jun 5, 2026
a105781
Merge pull request #436 from Producdevity/reduce-notification-polling
Producdevity Jun 5, 2026
d0f9673
Clean up session tracker code
Producdevity Jun 5, 2026
3fab7da
Merge pull request #433 from Producdevity/refactor/code-quality-todos
Producdevity Jun 6, 2026
83c3628
Notify moderators about submitted reports
Producdevity Jun 6, 2026
fd17056
Remove Vercel analytics integrations
Producdevity Jun 6, 2026
172be73
Merge pull request #437 from Producdevity/fix/session-tracking-metrics
Producdevity Jun 6, 2026
b84bbcd
refactor handheld comment creation
Producdevity Jun 6, 2026
c596f64
Refine report notification handling
Producdevity Jun 6, 2026
7142dd1
Align report submission errors
Producdevity Jun 6, 2026
5e4e835
Handle first-comment analytics failures
Producdevity Jun 6, 2026
d9d61db
Merge pull request #438 from Producdevity/fix/moderator-report-notifi…
Producdevity Jun 6, 2026
24639ef
Merge pull request #439 from Producdevity/refactor/comment-create-ser…
Producdevity Jun 6, 2026
7cec92b
refactor: simplify unverify logic in GenericVerifyButton
Producdevity Jun 6, 2026
aaf0c70
Remove Supabase-specific backup script and update generic backup logic
Producdevity Jun 7, 2026
678497f
fix: GA datalayer warning
Producdevity Jun 7, 2026
bf4736c
fix: update cache strategy and error handling in retrocatalog route
Producdevity Jun 7, 2026
446bde7
feat: add PC processed listings page and related functionality
Producdevity Jun 8, 2026
be26f58
Merge pull request #440 from Producdevity/feat/pc-processed-listings
Producdevity Jun 8, 2026
373dcdf
refactor: streamline error handling and role validation in TRPC helpers
Producdevity Jun 8, 2026
93e90f3
refactor: reorganize routers and update PC listing report functionality
Producdevity Jun 8, 2026
e9843e7
refactor: remove unused schemas and streamline PC listing validation
Producdevity Jun 9, 2026
ab8d895
refactor: remove V2 listing components and associated logic
Producdevity Jun 11, 2026
1f850d0
refactor: consolidate admin hooks under a common module and update im…
Producdevity Jun 11, 2026
a36606d
refactor: centralize remote image patterns and proxy logic, update re…
Producdevity Jun 11, 2026
19f30c7
refactor: create a feature/domain-based architecture, started with CP…
Producdevity Jun 13, 2026
a5e414c
fix: move report moderation out of routers
Producdevity Jun 13, 2026
b5173cd
fix: harden pc listing moderation workflows
Producdevity Jun 13, 2026
92bfd2d
chore: update AGENTS.md with rules about types/interfaces
Producdevity Jun 15, 2026
983ff70
refactor: always use async listing filters
Producdevity Jun 16, 2026
b53567c
fix: align handheld and PC report workflows
Producdevity Jun 16, 2026
8faf6ca
chore: clean stale api compatibility wording
Producdevity Jun 16, 2026
efc6fea
fix: keep navbar auth hydration stable
Producdevity Jun 16, 2026
9d49ae1
refactor: remove deprecated image proxy logic, replace with provider-…
Producdevity Jun 17, 2026
0faa8ce
fix: stabilize async filter e2e selection
Producdevity Jun 17, 2026
05b39fd
Merge pull request #441 from Producdevity/refactor/split-pclistings-r…
Producdevity Jun 19, 2026
b582e13
fix: correct default app URL in sitemap generator
Producdevity Jun 20, 2026
9eade60
fix: replace polling intervals with window focus refetch in listing e…
Producdevity Jun 20, 2026
aa5a8c7
refactor: add unit tests for mobile context, proxy handling, Steam ba…
Producdevity Jun 30, 2026
30a0fcd
test: update mobile context authentication behavior
Producdevity Jul 7, 2026
20c5f32
docs: update mobile API documentation and API key handling
Producdevity Jul 7, 2026
32ef4dc
Merge pull request #454 from Producdevity/feat/server-hardening
Producdevity Jul 22, 2026
c852bbe
test: add handheld listing repository tests and fix search filters
Producdevity Aug 22, 2026
43e7bdf
test: cover pending listing visibility by role
Producdevity Aug 22, 2026
8cbc269
Merge pull request #467 from Producdevity/feat/server-hardening
Producdevity Aug 22, 2026
fdf80a7
chore: prepare v0.15.0 release
Producdevity Aug 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 0 additions & 3 deletions .env.docker.example
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ NEXT_PUBLIC_GA_ID="your_google_analytics_id_here"
NEXT_PUBLIC_APP_ENV=local
NEXT_PUBLIC_LOCAL_STORAGE_PREFIX="@DockerEmuReady_"
NEXT_PUBLIC_EMUREADY_BETA_URL="https://play.google.com/store/apps/details?id=com.producdevity.emureadyapp"
NEXT_PUBLIC_VERCEL_ANALYTICS_ENABLED=false
NEXT_PUBLIC_ENABLE_ANALYTICS=false
NEXT_PUBLIC_ENABLE_KOFI_WIDGET=false
NEXT_PUBLIC_ENABLE_SENTRY=false
Expand All @@ -77,8 +76,6 @@ NEXT_PUBLIC_GITHUB_URL="https://github.com/Producdevity/EmuReady"
NEXT_PUBLIC_EMUREADY_LITE_GITHUB_URL="https://github.com/Producdevity/EmuReadyLite/releases"
NEXT_PUBLIC_APP_URL="https://dev.emuready.com"
NEXT_PUBLIC_ENABLE_SW=false
NEXT_PUBLIC_ENABLE_ASYNC_LISTINGS_FILTERS=false
NEXT_PUBLIC_ENABLE_V2_LISTINGS=false
NEXT_TELEMETRY_DISABLED=1
NEXT_IMAGE_UNOPTIMIZED=false

Expand Down
3 changes: 0 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ NEXT_PUBLIC_APP_ENV=local
NEXT_PUBLIC_GA_ID="Google-Analytics-ID"
NEXT_PUBLIC_LOCAL_STORAGE_PREFIX="@LocalEmuReady_"
NEXT_PUBLIC_EMUREADY_BETA_URL="https://play.google.com/store/apps/details?id=com.producdevity.emureadyapp"
NEXT_PUBLIC_VERCEL_ANALYTICS_ENABLED=false
NEXT_PUBLIC_ENABLE_ANALYTICS=false
NEXT_PUBLIC_ENABLE_KOFI_WIDGET=false
NEXT_PUBLIC_ENABLE_SENTRY=false
Expand All @@ -52,8 +51,6 @@ NEXT_PUBLIC_EMUREADY_LITE_GITHUB_URL="https://github.com/Producdevity/EmuReadyLi
NEXT_PUBLIC_APP_URL="http://localhost:3000" # Make sure to change this if you are using a tunnel
NEXT_PUBLIC_ENABLE_SW=false
NEXT_PUBLIC_ENABLE_PATREON_VERIFICATION=true
NEXT_PUBLIC_ENABLE_ASYNC_LISTINGS_FILTERS=false
NEXT_PUBLIC_ENABLE_V2_LISTINGS=false
NEXT_TELEMETRY_DISABLED=1
NEXT_IMAGE_UNOPTIMIZED=false

Expand Down
3 changes: 0 additions & 3 deletions .env.test.example
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ NEXT_PUBLIC_APP_ENV=test
NEXT_PUBLIC_GA_ID=""
NEXT_PUBLIC_LOCAL_STORAGE_PREFIX="@TestEmuReady_"
NEXT_PUBLIC_EMUREADY_BETA_URL="https://play.google.com/store/apps/details?id=com.producdevity.emureadyapp"
NEXT_PUBLIC_VERCEL_ANALYTICS_ENABLED=false
NEXT_PUBLIC_ENABLE_ANALYTICS=false
NEXT_PUBLIC_ENABLE_KOFI_WIDGET=false
NEXT_PUBLIC_ENABLE_SENTRY=false
Expand All @@ -41,8 +40,6 @@ NEXT_PUBLIC_APP_URL="https://dev.emuready.com"
NEXT_PUBLIC_ENABLE_PATREON_VERIFICATION=true
NEXT_PUBLIC_ENABLE_SW=false
NEXT_PUBLIC_DISABLE_COOKIE_BANNER=true
NEXT_PUBLIC_ENABLE_ASYNC_LISTINGS_FILTERS=false
NEXT_PUBLIC_ENABLE_V2_LISTINGS=false
NEXT_TELEMETRY_DISABLED=1
NEXT_IMAGE_UNOPTIMIZED=true

Expand Down
55 changes: 51 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,53 @@ This file is the source of working guidance for AI coding agents in this reposit
- Feature folders should follow the project-structure guidance from Bulletproof React:
https://github.com/alan2207/bulletproof-react/blob/master/docs/project-structure.md
- Within `src/features/*`, prefer scoped subdirectories such as `components`, `hooks`, `utils`, `server`, and `shared` instead of flat feature folders.
- Routers in `src/server/api/routers/` are thin orchestration layers. They handle auth context, schema-validated input, repository/service calls, and response formatting.
- Feature-owned modules may colocate client, server, and shared code under
`src/features/<domain>/<module>/`.
- Use this feature module structure for new or actively-refactored domain code:
- `shared/` contains Zod schemas, types, constants, and pure formatting helpers usable by client and server.
- `server/` contains repositories, services, policies, mappers, and feature-owned tRPC routers.
- `client/` contains hooks, reusable components, and workflow views. Add client API wrappers only when they remove real duplication or encode a stable UI contract.
- `client/admin/` is allowed for admin-only workflows.
- Import direction matters more than folder names:
- `client/` may import from its feature `shared/` and app-wide client-safe utilities.
- `server/` may import from its feature `shared/`, server utilities, and repositories.
- `shared/` must not import from `client/`, `server/`, `src/app`, or server-only libraries.
- `src/app/**` routes/pages should compose feature modules; feature modules should not import from `src/app/**`.
- tRPC routers are transport adapters. Feature-specific routers should live in the feature `server/` folder when that feature owns the full use case; `src/server/api/root.ts` should only compose them.
- Legacy routers in `src/server/api/routers/` are thin orchestration layers. They handle auth context, schema-validated input, repository/service calls, and response formatting.
- Do not put raw Prisma queries or business logic in routers.
- Define Zod schemas in `src/schemas/*`; do not define inline schemas in router `.input(...)` calls.
- All database access belongs in repository classes under `src/server/repositories/` extending `BaseRepository`.
- Define Zod schemas in feature `shared/*.schemas.ts` for feature-owned code, or in `src/schemas/*` for legacy/shared code. Do not define inline schemas in router `.input(...)` calls.
- Feature-owned tRPC procedures should declare `.output(...)` with Zod schemas. Compatibility transports that must keep legacy shapes should still have explicit legacy output schemas instead of returning raw Prisma payloads by convention.
- All database access belongs in repository classes. Feature-owned repositories may live in feature `server/` folders; legacy/shared repositories may remain under `src/server/repositories/`.
- New or actively-refactored feature-owned Prisma repositories should extend `PrismaRepository` or `PrismaWriteRepository` from `src/server/persistence/prisma.repository.ts` for Prisma client ownership and shared write handling. Do not extend the legacy `BaseRepository` unless the inherited behavior is deliberately required and documented.
- Do not add generic CRUD methods to shared repository bases. Prisma already provides typed CRUD; feature repositories should expose domain/use-case persistence operations with named select contracts.
- For feature-owned Prisma repositories, prefer a `server/persistence/` subfolder for named `select` contracts, query builders, and Prisma error translation. Derive repository record types from Prisma `GetPayload` plus those named `select` contracts instead of hand-maintaining structural copies.
- Services should depend on the concrete feature repository by default. Do not add service-owned `Pick<Repository, ...>` contracts only for tests.
- Add repository interfaces only for real boundaries: multiple implementations, external provider adapters, lifecycle concerns that route composition cannot handle directly, or domain/application layers that intentionally must not depend on infrastructure.
- Repositories should use project error helpers and consistent database operation handling.
- Multi-step business logic, external API orchestration, and complex calculations belong in services under `src/server/services/`.
- Multi-step business logic, external API orchestration, and complex calculations belong in services under feature `server/` folders or legacy `src/server/services/`.
- Use policy functions for reusable authorization/business access rules that must be shared across transports. Routers may still use broad auth procedures, but services should enforce feature-level capabilities when the use case can be called from multiple transports.
- Use `AppError` and `ResourceError` helpers instead of raw `Error`, raw strings, or one-off `TRPCError` usage.
- Use specialized procedures such as `protectedProcedure`, `adminProcedure`, and `permissionProcedure(...)` instead of ad hoc permission checks.

## API Compatibility And Legacy Contracts

- Before introducing any `legacy` select, repository method, route, endpoint,
schema, type, mapper, compatibility branch, or response shape, audit known
consumers first. For mobile/public API work, this includes
`/Volumes/T9/Coding/personal/2026/Emulation/EmuReadyApp` when it is available,
or a temporary clone of `Producdevity/EmuReadyApp` on the `master` branch when
the local app checkout is unavailable or not production-synced.
- Record which fields consumers actually read. Do not preserve fields only
because they existed in an old Prisma payload, old inferred type, or old API
response.
- Decide compatibility case by case: remove unused old fields, migrate the
consumer, keep one standardized endpoint with a small low-cost superset, or
keep a separate legacy contract only when the audited consumer behavior truly
requires it.
- Legacy contracts must have an owner, a reason, and an expected removal path.
Remove legacy code as soon as audited consumers do not need it.

## Database And Prisma

- Treat database changes as high risk.
Expand All @@ -60,11 +98,20 @@ This file is the source of working guidance for AI coding agents in this reposit
- Do not use casts to hide type problems. Fix the underlying type issue.
- Handle null and undefined explicitly.
- Use generated Prisma types where appropriate.
- Prefer deriving types from existing contracts instead of hand-maintaining
structural copies. Use Prisma `GetPayload`, Zod `z.input`/`z.output`, tRPC
`RouterInput`/`RouterOutput`, `ReturnType`, and `typeof` on const contracts
before adding a new interface or structural type alias. Add new manual
interfaces/types only for genuinely new UI/application state or external
boundaries that cannot be inferred, and keep them narrow and local.
- Do not add unused functions, exports, or speculative helpers.
- Remove dead code when refactoring.
- Do not remove or rewrite existing TODO comments unless the user explicitly
asks, or unless the TODO is directly made obsolete by the code change.
- Prefer function declarations for top-level functions/components.
- Avoid object destructuring when values are used only once or when it makes
ownership less clear. Prefer `object.property` access unless destructuring
materially improves readability.
- Component props interfaces should be named `Props`.
- Do not destructure component props in function parameters; use `props.foo`.
- Keep `useEffect` dependencies correct.
Expand Down
40 changes: 40 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,43 @@
# 🚀 EmuReady Release Notes – 22 August 2026 (v0.15.0)

v0.15.0 brings the PC moderation workflow up to parity with handheld reports, hardens the web and mobile API paths, and cuts unnecessary server traffic. It also includes a set of smaller fixes across report browsing, comments, notifications, admin tools, and GameNative configuration.

## Users

- Handheld report search now combines the search term with approval and ownership rules correctly. Signed-out users see matching approved reports, signed-in users also see their own matching pending reports, and unrelated reports no longer leak into the results.
- Comments and replies can now be submitted with Cmd+Enter or Ctrl+Enter without bypassing validation or human-verification checks.
- Oversized cover art no longer pushes handheld or PC report detail cards outside their containers.
- Translation language detection now loads only when translated content is near the viewport, and cached translated text is reset when the source content changes.
- Notification lists load only while the notification menu is open. The unread badge refreshes less often in the background and refreshes again when the menu is opened.
- Handheld and PC report filters now use the async selectors consistently instead of depending on feature flags.
- New GameNative configurations now default `startup_selection` to Essential, matching the generated configuration.

## Moderators and admins

- Added a processed PC reports page with status filtering, search, sorting, pagination, status overrides, and reset-to-pending actions.
- Handheld and PC processed-report actions now share the same admin UI and keep trust changes, notifications, and cache invalidation aligned.
- Moderator-role users and above now receive notifications when handheld or PC reports are submitted through the web or mobile API.
- Report submission and moderation paths now share more of their validation and persistence logic, including description sanitization for PC and mobile submissions.
- Custom field template search now matches template names, descriptions, field names, and field labels, with a separate empty state when no filtered results match.
- CPU and GPU admin pages now request the correct brand category from the server instead of maintaining client-side brand allowlists.
- IGDB image selection is available to moderators while the normal author flow keeps its existing RAWG and TheGamesDB choices.
- Admin pages use more of the shared layout, error, statistics, and empty-state components. Deleting an in-use performance scale now completes its replacement step before removal.

## Developers and contributors

- Anonymous public GET lookups can use shared-cache headers. Authenticated requests, errors, batches, mutations, and requests carrying credentials remain `private, no-store`.
- Mobile CORS and origin handling were standardized. Browser requests with untrusted origin metadata are rejected, while native clients without browser origin headers continue to work.
- Explicit invalid `Authorization: ApiKey ...` credentials are rejected. The legacy `x-api-key` fallback remains temporarily permissive for shipped mobile clients that also use Bearer authentication.
- Steam batch lookup now uses one shared service for the mobile API and admin tools, preserves the requested App ID order, and returns explicit not-found results.
- CPU and GPU code now lives in feature-owned modules with shared contracts, repositories, services, policies, mappers, routers, and admin components.
- Mobile API documentation and generated OpenAPI output were refreshed for the current authentication, validation, hardware lookup, report, and Steam batch contracts.
- Game image handling now uses provider-aware validation and rendering, and the deprecated image proxy path was removed.
- Removed unused realtime notification/SSE code, Vercel Analytics integration, old popup code, and the experimental v2 listings implementation.
- Session analytics now derive sign-in method, page views, and interaction counts from actual client activity instead of placeholder values.
- Test coverage was expanded for mobile authentication, proxy origin handling, CORS, tRPC cache policy, Steam batch lookups, CPU/GPU modules, PC moderation, notifications, session tracking, admin search, report layout, and search visibility across user roles.

---

# 🚀 EmuReady Release Notes – 4 June 2026 (v0.14.0)

This update is smaller than the v0.13.0 catch-up release, but it touches some important day-to-day workflows. The main themes are safer moderation, better spam protection, faster report browsing, and fewer stale-cache issues. Routine cleanup, small dependency churn, and test-only refactors are omitted unless they affect users, moderators, or maintenance.
Expand Down
25 changes: 25 additions & 0 deletions config/image-hosts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export const GAME_IMAGE_PROVIDER_HOST_PATTERNS = [
'media.rawg.io',
'cdn.thegamesdb.net',
'images.igdb.com',
'assets.nintendo.com',
'shared.akamai.steamstatic.com',
'cdn1.epicgames.com',
'cdn2.unrealengine.com',
'images.gog-statics.com',
] as const

export const NEXT_IMAGE_REMOTE_HOST_PATTERNS = [
'placehold.co',
'*.clerk.com',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: When a nested Clerk subdomain reaches ImageRenderer, this pattern makes the shared matcher select next/image, but Next only allows one subdomain for *.clerk.com. Make the matcher and Next pattern semantics identical, or replace the wildcard with the exact Clerk image hosts, so these URLs use the correct rendering path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At config/image-hosts.ts, line 14:

<comment>When a nested Clerk subdomain reaches `ImageRenderer`, this pattern makes the shared matcher select `next/image`, but Next only allows one subdomain for `*.clerk.com`. Make the matcher and Next pattern semantics identical, or replace the wildcard with the exact Clerk image hosts, so these URLs use the correct rendering path.</comment>

<file context>
@@ -0,0 +1,25 @@
+
+export const NEXT_IMAGE_REMOTE_HOST_PATTERNS = [
+  'placehold.co',
+  '*.clerk.com',
+  '*.clerk.accounts.dev',
+  'storage.ko-fi.com',
</file context>

'*.clerk.accounts.dev',
'storage.ko-fi.com',
'ko-fi.com',
...GAME_IMAGE_PROVIDER_HOST_PATTERNS,
] as const

export const NEXT_IMAGE_REMOTE_PATTERNS = NEXT_IMAGE_REMOTE_HOST_PATTERNS.map((hostname) => ({
protocol: 'https' as const,
hostname,
pathname: '/**',
}))
Loading
Loading