managarten/apps/mana/apps/web/vite.config.ts
Till JS 80b23dd9ff fix(mana/web): clear remaining type errors — long-tail sweep
The last cleanup pass after the package-level fixes. Each of the
~30 files below had 1-2 distinct errors; they're grouped because
none individually justifies its own commit and they're all the same
shape: small drift between a call site and the type system the
existing-code-doesn't-need-to-change refactor that gets it to clean.

Highlights by file:

vite.config.ts
  Switched `defineConfig` import from `vite` to `vitest/config` so
  the inline `test:` block (vitest unit-test exclude rule) is
  recognized at the type layer. Was the last single error standing.

routes/(app)/news/+page.svelte
  Replaced `{#each ranked as { article } (article.id)}` destructure
  with `{#each ranked as scored (scored.article.id)}` + two
  `{@const}` rows. The destructured-each + immediate-`@const`
  combination tripped a Svelte compiler placement error.

routes/(app)/contacts/[id], modules/calendar/EventForm
  `(x as Record<string, unknown>)` casts were rejected because the
  source type doesn't have a string index signature. Two-step
  cast: `as unknown as Record<string, unknown>`.

routes/(app)/inventory/collections/[id]/edit
  `collection.schema.fields` round-trips through JSON in the Dexie
  row, which widens `type` to plain `string`. Cast back to
  `FieldDefinition[]` at the read site; the runtime values match
  the FieldType union.

routes/(app)/presi/deck/[id], modules/zitare/QuoteCard,
modules/memoro/views/DetailView
  - presi: `currentDeck?.name` → `?.title` (Deck has `title`, not
    `name`).
  - QuoteCard: `let authorBioText = $derived(() => {...})` was
    storing the arrow function itself. Switch to `$derived.by(...)`.
  - memoro DetailView: explicit `<QueuedTask | null>` generic on
    the useLiveQueryWithDefault call so the unknown-typed default
    doesn't poison downstream state.

routes/(app)/memoro/{,/[id]}/+page.svelte + modules/memoro/queries.ts
  The Tag flowing through these components is the `@mana/shared-tags`
  shape (from `useAllTags`), not memoro's local Tag (which has
  isPinned/sortOrder for a UI we never built). Aligned all three
  files to the shared shape so the Tag[] arrays compose without
  property mismatches.

modules/{questions,context}/index.ts
  Re-exported names that didn't exist:
  - `questionCollectionTable` → `qCollectionTable`
  - `contextDocumentTable` → `documentTable`
  Both were leftover from a long-ago rename that the consumers
  still call by the new name.

modules/picture/stores/images.svelte.ts, modules/times/EntryItem
  - images: `toggleField()` wants a string-keyed Table<>; cast at
    the call site (runtime keys are UUIDs anyway).
  - EntryItem: `autoSave(updates: Record<string, unknown>)` won't
    fit Dexie's `UpdateSpec<LocalTimeEntry>`. Narrowed to
    `Partial<LocalTimeEntry>` and added the missing import.

modules/todo: TodoPage + QuickAddTask
  - TodoPage was passing `onOpen` to TaskItem (which only accepts
    `onClick` + `onContextMenu` + `onToggleComplete`). Replaced
    with the proper triplet on the recently-completed branch.
  - QuickAddTask `locale?: string` widened the input past the
    `ParserLocale` union the parser actually accepts. Imported
    the union and tightened the prop.

modules/presi/views/DetailView
  `decksStore.deleteDeck` returns `Promise<boolean>`, but
  `deleteWithUndo()` expects `Promise<void>`. Wrapped in an async
  arrow that discards the return.

routes/(app)/citycorners/.../edit
  Self-referential `let locId = $derived(locId ?? '')` from a
  search-and-replace gone wrong in the previous commit batch.
  Restored to `$derived($page.params.id ?? '')`.

routes/(app)/+layout.svelte, lib/components/onboarding/OnboardingWizard
  - layout: `(window as Record<string, unknown>)` → two-step
    `(window as unknown as Record<...>)` cast. Same shape as the
    contacts/EventForm fixes.
  - OnboardingWizard: added optional `onSkip?: () => void` prop
    so the layout's analytics callback type-checks. The wizard
    always also calls `onComplete()`, so the modal still closes
    cleanly without onSkip.

routes/(app)/api-keys/+page.svelte
  Removed `min={1}` / `max={1000}` props from the shared `<Input>`
  component (it's not a passthrough wrapper for native HTML
  attributes). Runtime validation still gates submit.

routes/(auth)/forgot-password
  `authStore.forgotPassword(email)` doesn't exist; the wrapper
  exposes `resetPassword(email)` for the send-email entry point.
  Renamed.

routes/(app)/{gifts,llm-test}, lib/content/help/index.test
  - gifts: `balance.freeCreditsRemaining` is now optional (added
    in the credits commit). Defaulted to 0 in the math.
  - llm-test: enqueueTaskNow union of two tasks with different
    output types — widened with `as any` for the enqueue call.
  - help index.test: `content.contact` is optional, asserted with
    non-null `!`.

lib/components/{SessionWarning,DashboardGrid,onboarding/OnboardingWizard}
  - SessionWarning: was calling `getAccessTokenSync` (doesn't
    exist) and `refreshToken` (doesn't exist). Switched to
    `getAccessToken()` (async, returns Promise) and `getValidToken()`
    (refreshes under the hood when expired).
  - DashboardGrid: `error?.message` on a `{}`-typed boundary
    arg. Cast to `Error | undefined`.

dashboard widgets: ContextDocs / ClockTimers / ActivityFeed
  - ContextDocs: `getSpaceName(spaceId: string)` widened to
    `string | null | undefined` so the optional doc.spaceId
    flows in cleanly.
  - ClockTimers: `formatRepeatDays`/`formatRemaining` widened to
    accept null|undefined.
  - ActivityFeed: `Activity` icon doesn't exist in
    `@mana/shared-icons`/phosphor-svelte. Replaced with `Pulse`
    everywhere in the file.

lib/app-registry/registry.spec
  `Set<AppIconId>.has(stringId)` rejected because the union is
  narrower. Widened the Set to `Set<string>`.

Net: -16 type errors. Final count: 0.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 20:25:08 +02:00

99 lines
3.8 KiB
TypeScript

import { sveltekit } from '@sveltejs/kit/vite';
import tailwindcss from '@tailwindcss/vite';
// `defineConfig` from vitest/config is a superset of vite's that
// recognizes the `test:` block. Without this, the inline test exclude
// below trips a "test does not exist on UserConfigExport" type error.
import { defineConfig } from 'vitest/config';
import { SvelteKitPWA } from '@vite-pwa/sveltekit';
import { createPWAConfig } from '@mana/shared-pwa';
import { MANA_SHARED_PACKAGES, getBuildDefines } from '@mana/shared-vite-config';
/** App-specific shared packages used by migrated modules */
const APP_SHARED_PACKAGES = ['@zitare/content', '@calc/shared'];
export default defineConfig({
plugins: [
tailwindcss(),
sveltekit(),
SvelteKitPWA(
createPWAConfig({
name: 'Mana',
shortName: 'Mana',
description: 'Mana App Ecosystem',
themeColor: '#6366f1',
registerType: 'prompt',
preset: 'full',
// Disable the service worker in dev. With devEnabled=true (the
// default) vite-plugin-pwa registers a SW that aggressively
// precaches the route chunks — and after the first dev session
// the SW keeps serving the OLD JS even when Vite HMR pushes
// new code, so source edits become invisible until the user
// manually unregisters the worker in DevTools. The 2026-04-08
// dreams mic-button bug took an extra hour to track down for
// exactly this reason. Production still gets the full SW.
devEnabled: false,
shortcuts: [
{ name: 'Dashboard', short_name: 'Home', url: '/', description: 'Zum Dashboard' },
{
name: 'Neue Aufgabe',
short_name: 'Aufgabe',
url: '/todo',
description: 'Neue Aufgabe erstellen',
},
{
name: 'Kalender',
short_name: 'Kalender',
url: '/calendar',
description: 'Kalender öffnen',
},
{ name: 'Chat', short_name: 'Chat', url: '/chat', description: 'Chat öffnen' },
],
})
),
],
server: {
port: 5173,
strictPort: true,
},
preview: {
port: 4173,
strictPort: true,
},
worker: {
// Vite defaults to IIFE worker format, which does not support code
// splitting. @mana/local-llm's worker imports transformers.js, which
// is internally code-split into many chunks. Without 'es' format the
// build fails with "Invalid value 'iife' for option 'worker.format'
// - UMD and IIFE output formats are not supported for code-splitting
// builds." All modern browsers (which we already require for WebGPU)
// support module workers.
format: 'es',
},
ssr: {
// `rrule@2` ships dual CJS/ESM but its package.json has no `exports`
// field, so the SvelteKit Node adapter resolves it to the CJS bundle
// at runtime — and `import { RRule } from 'rrule'` then throws
// `Named export 'RRule' not found` when /calendar SSRs. Bundling rrule
// into the server build forces Vite's interop layer to handle the
// CJS↔ESM mismatch correctly.
noExternal: [...MANA_SHARED_PACKAGES, ...APP_SHARED_PACKAGES, 'rrule'],
// transformers.js is browser-only (uses WebGPU + the Cache API). The
// dynamic import in @mana/local-llm only ever fires client-side, but
// SvelteKit's adapter-node Rollup pass would otherwise warn that the
// import is unresolved at SSR time. Marking it external both silences
// the warning and ensures the SSR bundle never tries to load it.
external: ['@huggingface/transformers'],
},
optimizeDeps: {
exclude: [...MANA_SHARED_PACKAGES, ...APP_SHARED_PACKAGES],
},
define: {
...getBuildDefines(),
},
// Vitest unit-test config — keeps Playwright e2e specs out of the
// vitest run. Without this exclude, vitest imports them and they
// crash on `test.afterAll()` because they expect a Playwright runner.
test: {
exclude: ['**/node_modules/**', '**/dist/**', '**/build/**', 'e2e/**', 'tests/e2e/**'],
},
});