fix(vite): @/app.config alias must precede @ (first-match-wins)

@rollup/plugin-alias (which Vite uses) iterates alias entries in
definition order and uses the first match. Listing the broad '@' →
./src alias before the specific '@/app.config' → per-app override
means '@/app.config' is matched by '@' first and resolves to
./src/app.config — i.e. the hub config, not the standalone's.

For market this surfaced as:
  TypeError: Cannot read properties of undefined (reading 'config')
    at new NostrmarketAPI (nostrmarketAPI.ts:170:45)

(nostrmarketAPI reads appConfig.modules.market.config; the hub
config has only base.) The same bug affected castle (ExpensesAPI
reads modules.expenses.config) and wallet (WalletWebSocketService
reads modules.wallet.config.websocket) — both would crash on first
use even though their dev servers started fine. Castle and wallet
silently haven't been exercised yet in this session, so the bug
only surfaced from market.

Fix: put '@/app.config' first in the alias object in all 6
standalone vite configs (castle, market, wallet, chat, forum,
tasks). Comment added at each call site explaining the constraint.

The hub's vite.config.ts doesn't need the override — its
'@/app.config' resolves to ./src/app.config naturally, which IS
the hub config.

Activities (sortir) doesn't need the override either — its app.ts
imports from './app.config' (relative), and no module file under
src/modules/activities reads from '@/app.config'.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-05-02 14:53:40 +02:00
commit 14b81bf3eb
6 changed files with 16 additions and 8 deletions

View file

@ -105,10 +105,13 @@ export default defineConfig(({ mode }) => ({
], ],
resolve: { resolve: {
alias: { alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)), // ORDER MATTERS — @rollup/plugin-alias is first-match-wins.
// CRITICAL: Remap @/app.config to the castle app's config // The more specific @/app.config remap must precede the @ prefix
// ExpensesAPI and other modules import from @/app.config directly // alias, otherwise '@/app.config' matches '@' first and resolves
// to ./src/app.config (the hub config). ExpensesAPI etc. import
// from @/app.config and need the per-app config.
'@/app.config': fileURLToPath(new URL('./src/accounting-app/app.config.ts', import.meta.url)), '@/app.config': fileURLToPath(new URL('./src/accounting-app/app.config.ts', import.meta.url)),
'@': fileURLToPath(new URL('./src', import.meta.url)),
}, },
}, },
build: { build: {

View file

@ -98,8 +98,9 @@ export default defineConfig(({ mode }) => ({
], ],
resolve: { resolve: {
alias: { alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)), // ORDER MATTERS — @/app.config must precede @ (first-match-wins).
'@/app.config': fileURLToPath(new URL('./src/chat-app/app.config.ts', import.meta.url)), '@/app.config': fileURLToPath(new URL('./src/chat-app/app.config.ts', import.meta.url)),
'@': fileURLToPath(new URL('./src', import.meta.url)),
}, },
}, },
build: { build: {

View file

@ -98,8 +98,9 @@ export default defineConfig(({ mode }) => ({
], ],
resolve: { resolve: {
alias: { alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)), // ORDER MATTERS — @/app.config must precede @ (first-match-wins).
'@/app.config': fileURLToPath(new URL('./src/forum-app/app.config.ts', import.meta.url)), '@/app.config': fileURLToPath(new URL('./src/forum-app/app.config.ts', import.meta.url)),
'@': fileURLToPath(new URL('./src', import.meta.url)),
}, },
}, },
build: { build: {

View file

@ -98,8 +98,9 @@ export default defineConfig(({ mode }) => ({
], ],
resolve: { resolve: {
alias: { alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)), // ORDER MATTERS — @/app.config must precede @ (first-match-wins).
'@/app.config': fileURLToPath(new URL('./src/market-app/app.config.ts', import.meta.url)), '@/app.config': fileURLToPath(new URL('./src/market-app/app.config.ts', import.meta.url)),
'@': fileURLToPath(new URL('./src', import.meta.url)),
}, },
}, },
build: { build: {

View file

@ -98,8 +98,9 @@ export default defineConfig(({ mode }) => ({
], ],
resolve: { resolve: {
alias: { alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)), // ORDER MATTERS — @/app.config must precede @ (first-match-wins).
'@/app.config': fileURLToPath(new URL('./src/tasks-app/app.config.ts', import.meta.url)), '@/app.config': fileURLToPath(new URL('./src/tasks-app/app.config.ts', import.meta.url)),
'@': fileURLToPath(new URL('./src', import.meta.url)),
}, },
}, },
build: { build: {

View file

@ -104,8 +104,9 @@ export default defineConfig(({ mode }) => ({
], ],
resolve: { resolve: {
alias: { alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)), // ORDER MATTERS — @/app.config must precede @ (first-match-wins).
'@/app.config': fileURLToPath(new URL('./src/wallet-app/app.config.ts', import.meta.url)), '@/app.config': fileURLToPath(new URL('./src/wallet-app/app.config.ts', import.meta.url)),
'@': fileURLToPath(new URL('./src', import.meta.url)),
}, },
}, },
build: { build: {