chore(deps): SvelteKit 3 with adapter-static 4 and TypeScript 6, full-tree npm audit (#5021)

Merges Renovate's kit 3 (PR #149) and adapter-static 4 (PR #148) bumps,
plus the migration they need. The mechanical part is `sv migrate
sveltekit-3`, run one task at a time and reviewed:

- svelte.config.js is gone. Its options move into sveltekit() in
  vite.config.ts, exported as kitOptions so vitest.config.ts runs the
  same kit setup, including the $test-utils alias the tests import.
- $lib becomes #lib through package.json "imports". There is no
  src/lib/index, so only the "#lib/*" entry is kept.
- tsconfig extends $app/tsconfig.
- Peer floors raised to kit 3's requirements: svelte ^5.57.1, vite
  ^8.0.12, svelte-check ^4.7.5.

By hand, from the codemod's list of non-automated tasks:

- goto's replaceState option is now replace; keepFocus becomes
  reset: false. For the search typeahead, reset: false also stops the
  scroll-to-top, which is wanted while typing.
- The test setup mocks drop pushState/replaceState and $app/paths
  base/assets, which kit 3 removed, and mock refreshAll in place of
  invalidateAll.
- The other flagged files only read page.url or goto internal routes,
  so they needed no change.

TypeScript goes to ^6, not the ^7 Renovate offers: kit 3 declares
typescript ^6 as a peer and svelte-check 4.7 accepts ^5 || ^6. Move to
7 once both accept it.

With Tailwind 4 and kit 3 in, `npm audit` on the whole tree reports 0,
so the web lane now audits every dependency rather than only what
ships to browsers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 10:50:39 -04:00
co-authored by Claude Opus 5.5
186 changed files with 916 additions and 924 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import AdminTabs from '$lib/components/AdminTabs.svelte';
import AdminTabs from '#lib/components/AdminTabs.svelte';
let { children } = $props<{ children: import('svelte').Snippet }>();
</script>
+1 -1
View File
@@ -1,5 +1,5 @@
import { redirect } from '@sveltejs/kit';
import { user } from '$lib/auth/store.svelte';
import { user } from '#lib/auth/store.svelte.js';
import type { LayoutLoad } from './$types';
// Hard route gate: runs before the layout (and any child page) renders.
+9 -9
View File
@@ -1,8 +1,8 @@
<script lang="ts">
import { pageTitle } from '$lib/branding';
import { pageTitle } from '#lib/branding.js';
import { Disc3, Album, Music2, Check, X, RotateCcw, Trash2, Cloud, ChevronRight } from 'lucide-svelte';
import StageBadge from '$lib/components/StageBadge.svelte';
import LoudnessSettingsCard from '$lib/components/LoudnessSettingsCard.svelte';
import StageBadge from '#lib/components/StageBadge.svelte';
import LoudnessSettingsCard from '#lib/components/LoudnessSettingsCard.svelte';
import { stageState } from './stage-state';
import { useQueryClient } from '@tanstack/svelte-query';
import {
@@ -20,17 +20,17 @@
refetchMissingCovers,
triggerScan,
researchMissingArt
} from '$lib/api/admin';
import { qk } from '$lib/api/queries';
import { errCode } from '$lib/api/errors';
import { pushToast } from '$lib/stores/toast.svelte';
import { runMutation } from '$lib/util/runMutation';
} from '#lib/api/admin.js';
import { qk } from '#lib/api/queries.js';
import { errCode } from '#lib/api/errors.js';
import { pushToast } from '#lib/stores/toast.svelte.js';
import { runMutation } from '#lib/util/runMutation.js';
import type {
AdminQuarantineRow,
LidarrRequest,
LidarrRequestKind,
LidarrQuarantineReason
} from '$lib/api/types';
} from '#lib/api/types.js';
// Top-of-admin overview. Shows the connection card + the most recent
// 5 of each actionable queue (requests, quarantine) with inline
+3 -3
View File
@@ -8,7 +8,7 @@ const userState = vi.hoisted(() => ({
current: null as { id: string; username: string; is_admin: boolean } | null
}));
vi.mock('$lib/auth/store.svelte', () => ({
vi.mock('#lib/auth/store.svelte.js', () => ({
user: { get value() { return userState.current; } }
}));
@@ -16,7 +16,7 @@ vi.mock('$app/state', () => ({
page: { url: new URL('http://localhost/admin') }
}));
vi.mock('$lib/api/admin', async () => {
vi.mock('#lib/api/admin.js', async () => {
const { readable } = await import('svelte/store');
return {
createAdminRequestsQuery: vi.fn(),
@@ -106,7 +106,7 @@ import {
deleteQuarantineFile,
deleteQuarantineViaLidarr,
researchMissingArt
} from '$lib/api/admin';
} from '#lib/api/admin.js';
import OverviewPage from './+page.svelte';
function setupOverview(opts: {
@@ -1,5 +1,5 @@
<script lang="ts">
import { pageTitle } from '$lib/branding';
import { pageTitle } from '#lib/branding.js';
import { Copy, Download, Activity } from 'lucide-svelte';
import { useQueryClient } from '@tanstack/svelte-query';
import {
@@ -9,10 +9,10 @@
updateUserDebugMode,
type AdminDiagnostic,
type DiagnosticsFilter
} from '$lib/api/admin';
import { qk } from '$lib/api/queries';
import { errMessage } from '$lib/api/errors';
import { pushToast } from '$lib/stores/toast.svelte';
} from '#lib/api/admin.js';
import { qk } from '#lib/api/queries.js';
import { errMessage } from '#lib/api/errors.js';
import { pushToast } from '#lib/stores/toast.svelte.js';
// Device diagnostics timeline (M9). The operator enables debug-mode on
// an account (remotely, here), then watches the account's device(s)
+7 -7
View File
@@ -1,17 +1,17 @@
<script lang="ts">
import { pageTitle } from '$lib/branding';
import { pageTitle } from '#lib/branding.js';
import { Copy, TriangleAlert } from 'lucide-svelte';
import {
createDuplicatesQuery,
runDuplicateSweep,
dismissDuplicateGroup,
mergeDuplicateGroup
} from '$lib/api/admin';
import { errMessage } from '$lib/api/errors';
import { pushToast } from '$lib/stores/toast.svelte';
import { relativeTime } from '$lib/utils/relativeTime';
import type { AdminDuplicateGroup, AdminDuplicateMember } from '$lib/api/types';
import FingerprintSettingsCard from '$lib/components/FingerprintSettingsCard.svelte';
} from '#lib/api/admin.js';
import { errMessage } from '#lib/api/errors.js';
import { pushToast } from '#lib/stores/toast.svelte.js';
import { relativeTime } from '#lib/utils/relativeTime.js';
import type { AdminDuplicateGroup, AdminDuplicateMember } from '#lib/api/types.js';
import FingerprintSettingsCard from '#lib/components/FingerprintSettingsCard.svelte';
// Tracks the duplicate sweep believes hold one recording (#3912). Dismissing a
// group says "these are not duplicates", and the sweep will not propose that
@@ -1,9 +1,9 @@
import { afterEach, describe, expect, test, vi } from 'vitest';
import { fireEvent, render, screen } from '@testing-library/svelte';
import { mockQuery } from '../../../test-utils/query';
import type { AdminDuplicatesResponse } from '$lib/api/types';
import type { AdminDuplicatesResponse } from '#lib/api/types.js';
vi.mock('$lib/api/admin', () => ({
vi.mock('#lib/api/admin.js', () => ({
createDuplicatesQuery: vi.fn(),
runDuplicateSweep: vi.fn().mockResolvedValue({ started: true }),
dismissDuplicateGroup: vi.fn().mockResolvedValue(undefined),
@@ -29,7 +29,7 @@ import {
dismissDuplicateGroup,
mergeDuplicateGroup,
runDuplicateSweep
} from '$lib/api/admin';
} from '#lib/api/admin.js';
const HOUR = 3_600_000;
const ago = (ms: number) => new Date(Date.now() - ms).toISOString();
+11 -11
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import { tick } from 'svelte';
import { pageTitle } from '$lib/branding';
import { pageTitle } from '#lib/branding.js';
import { Save, RefreshCw, Trash2 } from 'lucide-svelte';
import { useQueryClient } from '@tanstack/svelte-query';
import {
@@ -22,16 +22,16 @@
type CoverProvider,
type TagProvider,
type SMTPConfig
} from '$lib/api/admin';
import { qk } from '$lib/api/queries';
import { errCode } from '$lib/api/errors';
import { pushToast } from '$lib/stores/toast.svelte';
import Modal from '$lib/components/Modal.svelte';
import AcoustIDCard from '$lib/components/AcoustIDCard.svelte';
import NetworkSettingsCard from '$lib/components/NetworkSettingsCard.svelte';
import PublicAddressCard from '$lib/components/PublicAddressCard.svelte';
import NotificationEmailCard from '$lib/components/NotificationEmailCard.svelte';
import type { LidarrConfig, LidarrTestResult } from '$lib/api/types';
} from '#lib/api/admin.js';
import { qk } from '#lib/api/queries.js';
import { errCode } from '#lib/api/errors.js';
import { pushToast } from '#lib/stores/toast.svelte.js';
import Modal from '#lib/components/Modal.svelte';
import AcoustIDCard from '#lib/components/AcoustIDCard.svelte';
import NetworkSettingsCard from '#lib/components/NetworkSettingsCard.svelte';
import PublicAddressCard from '#lib/components/PublicAddressCard.svelte';
import NotificationEmailCard from '#lib/components/NotificationEmailCard.svelte';
import type { LidarrConfig, LidarrTestResult } from '#lib/api/types.js';
// Lidarr connection panel. The "saved api key" is masked as "***" on GET —
// never displayed in the input. The input always starts empty; sending an
@@ -1,8 +1,8 @@
import { afterEach, describe, expect, test, vi } from 'vitest';
import { render, screen, fireEvent, waitFor, within } from '@testing-library/svelte';
import { mockQuery } from '../../../test-utils/query';
import type { LidarrConfig } from '$lib/api/types';
import type { CoverProvider, TagProvider, SMTPConfig } from '$lib/api/admin';
import type { LidarrConfig } from '#lib/api/types.js';
import type { CoverProvider, TagProvider, SMTPConfig } from '#lib/api/admin.js';
// useQueryClient is wrapped so the page can call invalidateQueries() without
// a real QueryClient context. Per-file mock OVERRIDES the vitest.setup default
@@ -13,7 +13,7 @@ vi.mock('@tanstack/svelte-query', async (orig) => {
return { ...actual, useQueryClient: () => ({ invalidateQueries }) };
});
vi.mock('$lib/api/admin', () => ({
vi.mock('#lib/api/admin.js', () => ({
createLidarrConfigQuery: vi.fn(),
createQualityProfilesQuery: vi.fn(),
createMetadataProfilesQuery: vi.fn(),
@@ -57,7 +57,7 @@ import {
createSMTPConfigQuery,
updateSMTPConfig,
testSMTPConfig
} from '$lib/api/admin';
} from '#lib/api/admin.js';
const cfgConnected: LidarrConfig = {
enabled: true,
@@ -1,11 +1,11 @@
<script lang="ts">
import { pageTitle } from '$lib/branding';
import { pageTitle } from '#lib/branding.js';
import { FolderX, Music2 } from 'lucide-svelte';
import { createMissingFilesQuery } from '$lib/api/admin';
import { relativeTime, timeUntil } from '$lib/utils/relativeTime';
import { coverUrl } from '$lib/media/covers';
import ReacquisitionSettingsCard from '$lib/components/ReacquisitionSettingsCard.svelte';
import type { AdminMissingGroup } from '$lib/api/types';
import { createMissingFilesQuery } from '#lib/api/admin.js';
import { relativeTime, timeUntil } from '#lib/utils/relativeTime.js';
import { coverUrl } from '#lib/media/covers.js';
import ReacquisitionSettingsCard from '#lib/components/ReacquisitionSettingsCard.svelte';
import type { AdminMissingGroup } from '#lib/api/types.js';
// Files the scan looked for and could not find. Read-only on purpose:
// a missing file keeps its track row, its play history and its likes,
@@ -1,12 +1,12 @@
import { afterEach, describe, expect, test, vi } from 'vitest';
import { render, screen } from '@testing-library/svelte';
import { mockQuery } from '../../../test-utils/query';
import type { AdminMissingResponse } from '$lib/api/types';
import type { AdminMissingResponse } from '#lib/api/types.js';
// The page now embeds ReacquisitionSettingsCard, which loads its own settings
// from this same module on mount. Stubbing both keeps these tests about the
// missing-files list — the card has its own suite.
vi.mock('$lib/api/admin', () => ({
vi.mock('#lib/api/admin.js', () => ({
createMissingFilesQuery: vi.fn(),
getReacquisitionSettings: vi.fn().mockResolvedValue({
enabled: true,
@@ -22,7 +22,7 @@ vi.mock('$lib/api/admin', () => ({
}));
import AdminMissingFilesPage from './+page.svelte';
import { createMissingFilesQuery } from '$lib/api/admin';
import { createMissingFilesQuery } from '#lib/api/admin.js';
const DAY = 24 * 3_600_000;
@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest';
import { stageState } from './stage-state';
import type { ScanStatus } from '$lib/api/admin';
import type { ScanStatus } from '#lib/api/admin.js';
const FINISHED_AT = '2026-05-06T12:00:00Z';
@@ -1,19 +1,19 @@
<script lang="ts">
import { pageTitle } from '$lib/branding';
import { pageTitle } from '#lib/branding.js';
import { Copy, Trash2, CheckCircle2 } from 'lucide-svelte';
import { useQueryClient } from '@tanstack/svelte-query';
import RowActionsMenu, { type RowAction } from '$lib/components/RowActionsMenu.svelte';
import RowActionsMenu, { type RowAction } from '#lib/components/RowActionsMenu.svelte';
import {
createAdminPlaybackErrorsQuery,
resolvePlaybackError,
deleteQuarantineFile
} from '$lib/api/admin';
import { qk } from '$lib/api/queries';
import { errMessage } from '$lib/api/errors';
import { pushToast } from '$lib/stores/toast.svelte';
import Modal from '$lib/components/Modal.svelte';
import type { AdminPlaybackError, PlaybackErrorResolution } from '$lib/api/types';
import { relativeTime } from '$lib/utils/relativeTime';
} from '#lib/api/admin.js';
import { qk } from '#lib/api/queries.js';
import { errMessage } from '#lib/api/errors.js';
import { pushToast } from '#lib/stores/toast.svelte.js';
import Modal from '#lib/components/Modal.svelte';
import type { AdminPlaybackError, PlaybackErrorResolution } from '#lib/api/types.js';
import { relativeTime } from '#lib/utils/relativeTime.js';
// Client-reported playback errors inbox. Two tabs — Unresolved
// (default) / Resolved. Per-row: copy details to clipboard, delete
+11 -11
View File
@@ -1,22 +1,22 @@
<script lang="ts">
import { pageTitle } from '$lib/branding';
import { pageTitle } from '#lib/branding.js';
import { Music2, RotateCcw, Trash2, Cloud, Play, ChevronRight } from 'lucide-svelte';
import { useQueryClient } from '@tanstack/svelte-query';
import RowActionsMenu, { type RowAction } from '$lib/components/RowActionsMenu.svelte';
import RowActionsMenu, { type RowAction } from '#lib/components/RowActionsMenu.svelte';
import {
createAdminQuarantineQuery,
resolveQuarantine,
deleteQuarantineFile,
deleteQuarantineViaLidarr
} from '$lib/api/admin';
import { qk } from '$lib/api/queries';
import { errMessage } from '$lib/api/errors';
import { pushToast } from '$lib/stores/toast.svelte';
import { playRadio } from '$lib/player/store.svelte';
import { coverUrl } from '$lib/media/covers';
import Modal from '$lib/components/Modal.svelte';
import type { AdminQuarantineRow, LidarrQuarantineReason } from '$lib/api/types';
import { relativeTime } from '$lib/utils/relativeTime';
} from '#lib/api/admin.js';
import { qk } from '#lib/api/queries.js';
import { errMessage } from '#lib/api/errors.js';
import { pushToast } from '#lib/stores/toast.svelte.js';
import { playRadio } from '#lib/player/store.svelte.js';
import { coverUrl } from '#lib/media/covers.js';
import Modal from '#lib/components/Modal.svelte';
import type { AdminQuarantineRow, LidarrQuarantineReason } from '#lib/api/types.js';
import { relativeTime } from '#lib/utils/relativeTime.js';
// Aggregated triage queue. One row per track, with per-row resolution
// actions: Resolve (clears reports), Delete file (Bronze; modal-confirm),
@@ -1,18 +1,18 @@
import { afterEach, describe, expect, test, vi } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/svelte';
import { mockQuery } from '../../../test-utils/query';
import type { AdminQuarantineRow } from '$lib/api/types';
import type { AdminQuarantineRow } from '#lib/api/types.js';
// Wrap useQueryClient so the page can call invalidateQueries() without a real
// QueryClient context. Everything else from svelte-query passes through.
vi.mock('$lib/api/admin', () => ({
vi.mock('#lib/api/admin.js', () => ({
createAdminQuarantineQuery: vi.fn(),
resolveQuarantine: vi.fn(),
deleteQuarantineFile: vi.fn(),
deleteQuarantineViaLidarr: vi.fn()
}));
vi.mock('$lib/player/store.svelte', () => ({
vi.mock('#lib/player/store.svelte.js', () => ({
playRadio: vi.fn()
}));
@@ -22,8 +22,8 @@ import {
resolveQuarantine,
deleteQuarantineFile,
deleteQuarantineViaLidarr
} from '$lib/api/admin';
import { playRadio } from '$lib/player/store.svelte';
} from '#lib/api/admin.js';
import { playRadio } from '#lib/player/store.svelte.js';
const baseRow: AdminQuarantineRow = {
track_id: 't-001',
+8 -8
View File
@@ -1,20 +1,20 @@
<script lang="ts">
import { pageTitle } from '$lib/branding';
import { pageTitle } from '#lib/branding.js';
import { Disc3, Album, Music2, Check, X, SlidersHorizontal } from 'lucide-svelte';
import { useQueryClient } from '@tanstack/svelte-query';
import RowActionsMenu, { type RowAction } from '$lib/components/RowActionsMenu.svelte';
import RowActionsMenu, { type RowAction } from '#lib/components/RowActionsMenu.svelte';
import {
createAdminRequestsQuery,
createQualityProfilesQuery,
createRootFoldersQuery,
approveRequest,
rejectRequest
} from '$lib/api/admin';
import { errMessage } from '$lib/api/errors';
import { pushToast } from '$lib/stores/toast.svelte';
import StatusPill from '$lib/components/StatusPill.svelte';
import Modal from '$lib/components/Modal.svelte';
import type { LidarrRequest, LidarrRequestKind, LidarrRequestStatus } from '$lib/api/types';
} from '#lib/api/admin.js';
import { errMessage } from '#lib/api/errors.js';
import { pushToast } from '#lib/stores/toast.svelte.js';
import StatusPill from '#lib/components/StatusPill.svelte';
import Modal from '#lib/components/Modal.svelte';
import type { LidarrRequest, LidarrRequestKind, LidarrRequestStatus } from '#lib/api/types.js';
// Approval queue. Tabs filter by status; rows expose Override/Approve/Reject
// per spec. The override modal collapses by default — most requests get the
@@ -1,11 +1,11 @@
import { afterEach, describe, expect, test, vi } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/svelte';
import { mockQuery } from '../../../test-utils/query';
import type { LidarrRequest } from '$lib/api/types';
import type { LidarrRequest } from '#lib/api/types.js';
// Wrap useQueryClient so the page can call invalidateQueries() without a
// real QueryClient context. Everything else from svelte-query passes through.
vi.mock('$lib/api/admin', () => ({
vi.mock('#lib/api/admin.js', () => ({
createAdminRequestsQuery: vi.fn(),
createQualityProfilesQuery: vi.fn(),
createRootFoldersQuery: vi.fn(),
@@ -20,7 +20,7 @@ import {
createRootFoldersQuery,
approveRequest,
rejectRequest
} from '$lib/api/admin';
} from '#lib/api/admin.js';
const baseRow: LidarrRequest = {
id: 'r1',
+1 -1
View File
@@ -1,4 +1,4 @@
import type { ScanStatus } from '$lib/api/admin';
import type { ScanStatus } from '#lib/api/admin.js';
export type StageState = 'pending' | 'in_progress' | 'done' | 'skipped';
+4 -4
View File
@@ -1,5 +1,5 @@
<script lang="ts">
import { pageTitle } from '$lib/branding';
import { pageTitle } from '#lib/branding.js';
import {
getTuning,
patchTuning,
@@ -14,9 +14,9 @@
type TrendsResponse,
type TrendSeries,
type TrendMarker
} from '$lib/api/tuning';
import { errMessage } from '$lib/api/errors';
import { pushToast } from '$lib/stores/toast.svelte';
} from '#lib/api/tuning.js';
import { errMessage } from '#lib/api/errors.js';
import { pushToast } from '#lib/stores/toast.svelte.js';
// The defaults-discovery lab (#1250): DB-backed scoring-weight
// profiles + taste-build knobs with live effect. This card exists to
+4 -4
View File
@@ -1,8 +1,8 @@
import { describe, expect, test, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/svelte';
import type { TuningSnapshot, TrendsResponse } from '$lib/api/tuning';
import type { TuningSnapshot, TrendsResponse } from '#lib/api/tuning.js';
vi.mock('$lib/api/tuning', async (orig) => {
vi.mock('#lib/api/tuning.js', async (orig) => {
const actual = (await orig()) as Record<string, unknown>;
return {
...actual,
@@ -14,10 +14,10 @@ vi.mock('$lib/api/tuning', async (orig) => {
});
const pushToast = vi.fn();
vi.mock('$lib/stores/toast.svelte', () => ({ pushToast: (...a: unknown[]) => pushToast(...a) }));
vi.mock('#lib/stores/toast.svelte.js', () => ({ pushToast: (...a: unknown[]) => pushToast(...a) }));
import TuningPage from './+page.svelte';
import { getTuning, patchTuning, resetTuning, getTrends } from '$lib/api/tuning';
import { getTuning, patchTuning, resetTuning, getTrends } from '#lib/api/tuning.js';
const weights = (over: Partial<Record<string, number>> = {}) => ({
base_weight: 1,
+7 -7
View File
@@ -1,7 +1,7 @@
<script lang="ts">
import { pageTitle } from '$lib/branding';
import { pageTitle } from '#lib/branding.js';
import { useQueryClient } from '@tanstack/svelte-query';
import { qk } from '$lib/api/queries';
import { qk } from '#lib/api/queries.js';
import {
updateUserAdmin,
createInvite,
@@ -15,11 +15,11 @@
type AdminUser,
type AdminInvite,
type CreateUserInput
} from '$lib/api/admin';
import { errCode } from '$lib/api/errors';
import { pushToast } from '$lib/stores/toast.svelte';
import Modal from '$lib/components/Modal.svelte';
import RowActionsMenu, { type RowAction } from '$lib/components/RowActionsMenu.svelte';
} from '#lib/api/admin.js';
import { errCode } from '#lib/api/errors.js';
import { pushToast } from '#lib/stores/toast.svelte.js';
import Modal from '#lib/components/Modal.svelte';
import RowActionsMenu, { type RowAction } from '#lib/components/RowActionsMenu.svelte';
import { Shield, ShieldOff, CheckCircle2, XCircle, KeyRound, Trash2, Copy } from 'lucide-svelte';
const client = useQueryClient();
+3 -3
View File
@@ -1,11 +1,11 @@
import { afterEach, describe, expect, test, vi } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/svelte';
import { mockQuery } from '../../../test-utils/query';
import type { AdminUser, AdminInvite } from '$lib/api/admin';
import type { AdminUser, AdminInvite } from '#lib/api/admin.js';
// Wrap useQueryClient so the page can call invalidateQueries() without a real
// QueryClient context. Everything else from svelte-query passes through.
vi.mock('$lib/api/admin', () => ({
vi.mock('#lib/api/admin.js', () => ({
createAdminUsersQuery: vi.fn(),
createAdminInvitesQuery: vi.fn(),
listUsers: vi.fn(),
@@ -30,7 +30,7 @@ import {
deleteUser,
resetUserPassword,
updateUserAutoApprove
} from '$lib/api/admin';
} from '#lib/api/admin.js';
const alice: AdminUser = {
id: 'u1',