From bab2c1c0d191fae6b982b466abdcb0466602e530 Mon Sep 17 00:00:00 2001 From: Owais Jamil Date: Tue, 9 Jun 2026 14:14:48 -0500 Subject: [PATCH] feat: document viewer --- CHANGELOG.md | 40 +-- package.json | 1 + pnpm-lock.yaml | 71 +++++ src/lib/atproto/repo.svelte.ts | 30 +- src/lib/components/CollectionBrowser.svelte | 4 +- src/lib/components/DocumentViewer.svelte | 140 +++++++++ src/lib/window-manager.svelte.ts | 13 +- src/routes/+layout.svelte | 83 +++-- src/routes/docs/CHANGELOG.md | 39 +++ src/routes/docs/[slug]/+page.svelte | 28 ++ src/routes/docs/[slug]/+page.ts | 28 ++ .../mimes/gnome-mime-application-pdf.svg | 290 ++++++++++++++++++ svelte.config.js | 3 + vite.config.ts | 23 ++ 14 files changed, 713 insertions(+), 80 deletions(-) mode change 100644 => 120000 CHANGELOG.md create mode 100644 src/lib/components/DocumentViewer.svelte create mode 100644 src/routes/docs/CHANGELOG.md create mode 100644 src/routes/docs/[slug]/+page.svelte create mode 100644 src/routes/docs/[slug]/+page.ts create mode 100644 static/icons/humanity/mimes/gnome-mime-application-pdf.svg diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index d357eb9..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,39 +0,0 @@ -# Changelog - -## [Unreleased] - -Target release: `v1.0.0`. - -### 2026-06-09 - -#### Added - -- PGlite-backed local cache/search foundation with WASM build support. - - Transactional schema migrations for accounts, cached records, collection - sync state, and record search. -- Ubuntu-purple boot splash that initializes PGlite, runs migrations, and offers - recovery actions. -- Cache-aware AT Protocol browsing: live record fetches populate PGlite and offline - failures can fall back to cached collections/records. -- Full-text cache search in the Nautilus-style collection browser. -- Atmosphere app logo mapping for known AT Protocol collection namespaces. -- Cursor-based record pagination with a generator-backed “Load more records” flow. - -#### Changed - -- Grouped Nautilus collections by top-level namespace folders. - -### 2026-06-08 - -#### Added - -- Ubuntu 8.10 / GNOME 2-inspired desktop shell, panel, wallpaper, windows, and Humanity - icon styling. -- First-run AT Protocol account setup flow with handle resolution and persisted account - identity. -- Nautilus-style collection browser backed by live AT Protocol repository collection and - record loading. -- gedit-style JSON record viewer opened from selected records. -- Window management basics including movable, resizable, minimizable, maximizable, and - closable windows. -- About Computer dialog, desktop icons, sticky note, and Tangled project links. diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 120000 index 0000000..103de7f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1 @@ +src/routes/docs/CHANGELOG.md \ No newline at end of file diff --git a/package.json b/package.json index 60a761b..d5f312e 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "eslint-config-prettier": "^10.1.8", "eslint-plugin-svelte": "^3.17.0", "globals": "^17.4.0", + "mdsvex": "^0.12.7", "playwright": "^1.60.0", "prettier": "^3.8.1", "prettier-plugin-svelte": "^3.5.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 68c9d6f..f36569f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -72,6 +72,9 @@ importers: globals: specifier: ^17.4.0 version: 17.6.0 + mdsvex: + specifier: ^0.12.7 + version: 0.12.7(svelte@5.56.3(@typescript-eslint/types@8.61.0)) playwright: specifier: ^1.60.0 version: 1.60.0 @@ -450,6 +453,9 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} @@ -957,6 +963,11 @@ packages: mdast-util-to-hast@13.2.1: resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + mdsvex@0.12.7: + resolution: {integrity: sha512-gx4bReLCUvq+MPErHXYeyX+TEq1hsS2KfiZtEOMNTcbibSouFy8AHc5h04KbGCl+g5tLuo4/lbgRVYRnc7bJZw==} + peerDependencies: + svelte: ^3.56.0 || ^4.0.0 || ^5.0.0-next.120 + micromark-util-character@2.1.1: resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} @@ -1096,6 +1107,13 @@ packages: engines: {node: '>=14'} hasBin: true + prism-svelte@0.4.7: + resolution: {integrity: sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ==} + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + property-information@7.2.0: resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} @@ -1242,18 +1260,30 @@ packages: unicode-segmenter@0.14.5: resolution: {integrity: sha512-jHGmj2LUuqDcX3hqY12Ql+uhUTn8huuxNZGq7GvtF6bSybzH3aFgedYu/KTzQStEgt1Ra2F3HxadNXsNjb3m3g==} + unist-util-is@4.1.0: + resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==} + unist-util-is@6.0.1: resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} unist-util-position@5.0.0: resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + unist-util-stringify-position@2.0.3: + resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} + unist-util-stringify-position@4.0.0: resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + unist-util-visit-parents@3.1.1: + resolution: {integrity: sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==} + unist-util-visit-parents@6.0.2: resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + unist-util-visit@2.0.3: + resolution: {integrity: sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==} + unist-util-visit@5.1.0: resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} @@ -1271,6 +1301,9 @@ packages: typescript: optional: true + vfile-message@2.0.4: + resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==} + vfile-message@4.0.3: resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} @@ -1727,6 +1760,8 @@ snapshots: '@types/trusted-types@2.0.7': {} + '@types/unist@2.0.11': {} + '@types/unist@3.0.3': {} '@typescript-eslint/eslint-plugin@8.61.0(@typescript-eslint/parser@8.61.0(eslint@10.4.1)(typescript@6.0.3))(eslint@10.4.1)(typescript@6.0.3)': @@ -2251,6 +2286,16 @@ snapshots: unist-util-visit: 5.1.0 vfile: 6.0.3 + mdsvex@0.12.7(svelte@5.56.3(@typescript-eslint/types@8.61.0)): + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 2.0.11 + prism-svelte: 0.4.7 + prismjs: 1.30.0 + svelte: 5.56.3(@typescript-eslint/types@8.61.0) + unist-util-visit: 2.0.3 + vfile-message: 2.0.4 + micromark-util-character@2.1.1: dependencies: micromark-util-symbol: 2.0.1 @@ -2364,6 +2409,10 @@ snapshots: prettier@3.8.3: {} + prism-svelte@0.4.7: {} + + prismjs@1.30.0: {} + property-information@7.2.0: {} punycode@2.3.1: {} @@ -2536,6 +2585,8 @@ snapshots: unicode-segmenter@0.14.5: {} + unist-util-is@4.1.0: {} + unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 @@ -2544,15 +2595,30 @@ snapshots: dependencies: '@types/unist': 3.0.3 + unist-util-stringify-position@2.0.3: + dependencies: + '@types/unist': 2.0.11 + unist-util-stringify-position@4.0.0: dependencies: '@types/unist': 3.0.3 + unist-util-visit-parents@3.1.1: + dependencies: + '@types/unist': 2.0.11 + unist-util-is: 4.1.0 + unist-util-visit-parents@6.0.2: dependencies: '@types/unist': 3.0.3 unist-util-is: 6.0.1 + unist-util-visit@2.0.3: + dependencies: + '@types/unist': 2.0.11 + unist-util-is: 4.1.0 + unist-util-visit-parents: 3.1.1 + unist-util-visit@5.1.0: dependencies: '@types/unist': 3.0.3 @@ -2569,6 +2635,11 @@ snapshots: optionalDependencies: typescript: 6.0.3 + vfile-message@2.0.4: + dependencies: + '@types/unist': 2.0.11 + unist-util-stringify-position: 2.0.3 + vfile-message@4.0.3: dependencies: '@types/unist': 3.0.3 diff --git a/src/lib/atproto/repo.svelte.ts b/src/lib/atproto/repo.svelte.ts index 5d667b6..fc3e3d3 100644 --- a/src/lib/atproto/repo.svelte.ts +++ b/src/lib/atproto/repo.svelte.ts @@ -1,26 +1,12 @@ import { Client, ok, simpleFetchHandler } from '@atcute/client'; import type { ActorIdentifier } from '@atcute/lexicons/syntax'; import type {} from '@atcute/atproto'; -import { - cacheFetchedRecords, - getDatabase, - listCachedCollections, - listCachedRecords, - searchCachedRecords, - updateCollectionSyncState, - type CachedRecord, - type CachedRecordInput -} from '$lib/db'; +import type { CachedRecord, CachedRecordInput } from '$lib/db'; import { errorMessage } from '$lib/utils/errors'; import { appLabelForCollection, collectionIconMatch } from './collection-icons'; import { listRecordPages, type RecordPage } from './pagination'; -import { - isRecordValue, - type AccountIdentity, - type CollectionSummary, - type RepoRecordSummary, - type UnknownRecord -} from './types'; +import { isRecordValue } from './types'; +import type { AccountIdentity, CollectionSummary, RepoRecordSummary, UnknownRecord } from './types'; export type { CollectionSummary, RepoRecordSummary } from './types'; @@ -125,12 +111,15 @@ class RepoBrowserState { async loadCollectionsFromCache(identity: AccountIdentity) { try { + const { getDatabase, listCachedCollections } = await import('$lib/db'); const db = await getDatabase(); const collections = await listCachedCollections(db, identity.did); if (collections.length === 0) return false; - this.collections = collections.map((collection) => collectionSummaryForName(collection.name, collection.loadedCount)); + this.collections = collections.map((collection) => + collectionSummaryForName(collection.name, collection.loadedCount) + ); this.selectedCollection = preferredCollection(this.collections.map((collection) => collection.name)); if (this.selectedCollection) { @@ -160,6 +149,7 @@ class RepoBrowserState { this.error = null; try { + const { getDatabase, searchCachedRecords } = await import('$lib/db'); const db = await getDatabase(); const results = await searchCachedRecords(db, normalizedQuery, { repoDid: identity.did, @@ -168,7 +158,7 @@ class RepoBrowserState { this.records = results.map((record) => summarizeCachedRecord(record, identity.handle)); } catch (searchError) { this.records = []; - this.error = errorMessage(searchError, 'Could not search cached records.'); + this.error = errorMessage(searchError, 'Could not search records.'); } finally { this.isSearching = false; } @@ -176,6 +166,7 @@ class RepoBrowserState { async loadRecordsFromCache(identity: AccountIdentity, collectionName: string) { try { + const { getDatabase, listCachedRecords } = await import('$lib/db'); const db = await getDatabase(); const records = await listCachedRecords(db, { repoDid: identity.did, collection: collectionName, limit: 25 }); @@ -269,6 +260,7 @@ async function cacheLiveRecords( cursor: string | null ) { try { + const { cacheFetchedRecords, getDatabase, updateCollectionSyncState } = await import('$lib/db'); const db = await getDatabase(); await cacheFetchedRecords( db, diff --git a/src/lib/components/CollectionBrowser.svelte b/src/lib/components/CollectionBrowser.svelte index 67e746a..f51a996 100644 --- a/src/lib/components/CollectionBrowser.svelte +++ b/src/lib/components/CollectionBrowser.svelte @@ -149,12 +149,12 @@ event.preventDefault(); searchRecords(); }}> - +
{#if repoBrowser.searchQuery} diff --git a/src/lib/components/DocumentViewer.svelte b/src/lib/components/DocumentViewer.svelte new file mode 100644 index 0000000..bd87be4 --- /dev/null +++ b/src/lib/components/DocumentViewer.svelte @@ -0,0 +1,140 @@ + + +
+ {#if Document} +
+ +
+ {:else} +
+ +

Document not found

+

Document Viewer could not open “{slug}”.

+
+ {/if} +
+ + diff --git a/src/lib/window-manager.svelte.ts b/src/lib/window-manager.svelte.ts index 4388d87..7f90306 100644 --- a/src/lib/window-manager.svelte.ts +++ b/src/lib/window-manager.svelte.ts @@ -1,4 +1,4 @@ -export type WindowId = 'main' | 'about-computer' | 'gedit'; +export type WindowId = 'main' | 'about-computer' | 'gedit' | 'document-viewer'; export type ManagedWindow = { id: WindowId; @@ -38,10 +38,19 @@ class WindowManager { isMinimized: false, isMaximized: false, zIndex: 3 + }, + { + id: 'document-viewer', + title: 'CHANGELOG.md - Document Viewer', + icon: '/icons/humanity/mimes/gnome-mime-application-pdf.svg', + isOpen: false, + isMinimized: false, + isMaximized: false, + zIndex: 4 } ]); - private nextZIndex = 3; + private nextZIndex = 4; get openWindows() { return this.windows.filter((window) => window.isOpen); diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 57d3f89..660f203 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -5,13 +5,13 @@ import { accountSetup } from '$lib/atproto/setup.svelte'; import favicon from '$lib/assets/favicon.svg'; import { desktopSession } from '$lib/desktop-session.svelte'; - import { getDatabase, resetLocalDatabase, runMigrations } from '$lib/db'; import { errorMessage } from '$lib/utils/errors'; import { windowManager } from '$lib/window-manager.svelte'; import AboutComputer from '$lib/components/AboutComputer.svelte'; import AppWindow from '$lib/components/AppWindow.svelte'; import BootSplash from '$lib/components/BootSplash.svelte'; import DesktopIcon from '$lib/components/DesktopIcon.svelte'; + import DocumentViewer from '$lib/components/DocumentViewer.svelte'; import Gedit from '$lib/components/Gedit.svelte'; import GnomePanel from '$lib/components/GnomePanel.svelte'; import LockScreen from '$lib/components/LockScreen.svelte'; @@ -27,6 +27,17 @@ let bootError = $state(null); let cacheDisabled = $state(false); + const windowTitle = $derived( + accountSetup.isConfigured ? 'AT Protocol Collections - Intrepid Ibex' : 'AT Protocol Account Setup' + ); + const windowIcon = $derived( + accountSetup.isConfigured ? '/icons/humanity/apps/internet-feed-reader.svg' : '/icons/humanity/places/user-home.svg' + ); + const mainWindow = $derived(windowManager.getWindow('main')); + const aboutWindow = $derived(windowManager.getWindow('about-computer')); + const geditWindow = $derived(windowManager.getWindow('gedit')); + const documentViewerWindow = $derived(windowManager.getWindow('document-viewer')); + const shortcuts = $derived([ { label: 'ibex Home', @@ -48,6 +59,12 @@ windowManager.open('about-computer'); } }, + { + label: 'Document Viewer', + icon: '/icons/humanity/mimes/gnome-mime-application-pdf.svg', + selected: documentViewerWindow?.isOpen && !documentViewerWindow.isMinimized, + onactivate: () => windowManager.open('document-viewer') + }, { label: 'Trash', icon: '/icons/humanity/places/user-trash.svg', @@ -55,16 +72,6 @@ } ]); - const windowTitle = $derived( - accountSetup.isConfigured ? 'AT Protocol Collections - Intrepid Ibex' : 'AT Protocol Account Setup' - ); - const windowIcon = $derived( - accountSetup.isConfigured ? '/icons/humanity/apps/internet-feed-reader.svg' : '/icons/humanity/places/user-home.svg' - ); - const mainWindow = $derived(windowManager.getWindow('main')); - const aboutWindow = $derived(windowManager.getWindow('about-computer')); - const geditWindow = $derived(windowManager.getWindow('gedit')); - $effect(() => { windowManager.setTitle('main', windowTitle, windowIcon); showAboutComputer = windowManager.getWindow('about-computer')?.isOpen ?? false; @@ -88,12 +95,22 @@ bootError = null; try { + const { getDatabase, getMigrationStatus, runMigrations } = await import('$lib/db'); + bootStep = 'Loading database'; const db = await getDatabase(); - bootStep = 'Applying migrations'; - await runMigrations(db); - bootStep = 'Starting desktop'; - await waitForMinimumBootTime(bootStartedAt); + bootStep = 'Checking migrations'; + const migrationStatus = await getMigrationStatus(db); + + if (migrationStatus.pending.length > 0) { + bootStep = 'Applying migrations'; + await runMigrations(db); + bootStep = 'Starting desktop'; + await waitForMinimumBootTime(bootStartedAt); + } else { + bootStep = 'Starting desktop'; + } + accountSetup.load(); bootStatus = 'ready'; } catch (error) { @@ -108,6 +125,7 @@ bootError = null; try { + const { resetLocalDatabase } = await import('$lib/db'); await resetLocalDatabase(); await bootDesktop(); } catch (error) { @@ -123,9 +141,8 @@ } async function waitForMinimumBootTime(startedAt: number) { - // TODO: this should be configurable/off after migrations are done - // We probably need to track app version - const remaining = 2500 - (performance.now() - startedAt); + const minimumBootTimeMs = 2500; + const remaining = minimumBootTimeMs - (performance.now() - startedAt); if (remaining > 0) { await new Promise((resolve) => setTimeout(resolve, remaining)); @@ -195,6 +212,26 @@
{/if} + {#if documentViewerWindow?.isOpen && !documentViewerWindow.isMinimized} +
+ windowManager.focus('document-viewer')} + onminimize={() => windowManager.minimize('document-viewer')} + onmaximize={() => windowManager.toggleMaximize('document-viewer')} + onclose={() => windowManager.close('document-viewer')}> + + +
+ {/if} + {#if repoBrowser.selectedRecord && geditWindow?.isOpen && !geditWindow.isMinimized}
+ import DocumentViewer from '$lib/components/DocumentViewer.svelte'; + + let { data }: { data: { slug: string } } = $props(); + + const title = $derived(titleFromSlug(data.slug)); + + function titleFromSlug(slug: string) { + return slug + .split('-') + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' '); + } + + + + {title} - Intrepid Ibex + + +
+ +
+ + diff --git a/src/routes/docs/[slug]/+page.ts b/src/routes/docs/[slug]/+page.ts new file mode 100644 index 0000000..5d2c08a --- /dev/null +++ b/src/routes/docs/[slug]/+page.ts @@ -0,0 +1,28 @@ +import { error } from '@sveltejs/kit'; +import type { EntryGenerator, PageLoad } from './$types'; + +const documents = import.meta.glob('../*.md'); + +function slugFromPath(path: string) { + return path + .split('/') + .at(-1) + ?.replace(/\.md$/, '') + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/^-|-$/g, ''); +} + +const documentSlugs = Object.keys(documents).map((path) => slugFromPath(path)).filter(Boolean) as string[]; + +export const entries: EntryGenerator = () => { + return documentSlugs.map((slug) => ({ slug })); +}; + +export const load: PageLoad = ({ params }) => { + if (!documentSlugs.includes(params.slug)) { + error(404, 'Document not found'); + } + + return { slug: params.slug }; +}; diff --git a/static/icons/humanity/mimes/gnome-mime-application-pdf.svg b/static/icons/humanity/mimes/gnome-mime-application-pdf.svg new file mode 100644 index 0000000..1072326 --- /dev/null +++ b/static/icons/humanity/mimes/gnome-mime-application-pdf.svg @@ -0,0 +1,290 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/svelte.config.js b/svelte.config.js index fea8d69..738efe1 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -1,7 +1,10 @@ import adapter from '@sveltejs/adapter-static'; +import { mdsvex } from 'mdsvex'; /** @type {import('@sveltejs/kit').Config} */ const config = { + extensions: ['.svelte', '.svx', '.md'], + preprocess: [mdsvex({ extensions: ['.svx', '.md'] })], compilerOptions: { runes: ({ filename }) => (filename.split(/[/\\]/).includes('node_modules') ? undefined : true) }, kit: { adapter: adapter() } }; diff --git a/vite.config.ts b/vite.config.ts index 21e95d5..be3055f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -6,6 +6,29 @@ export default defineConfig({ plugins: [sveltekit()], assetsInclude: ['**/*.wasm'], optimizeDeps: { exclude: ['@electric-sql/pglite'] }, + build: { + rolldownOptions: { + onLog(level, log, defaultHandler) { + const message = typeof log === 'string' ? log : log.message; + + /** + * PGlite currently emits Rolldown direct-eval warnings from its own + * packaged code. The app lazy-loads PGlite behind DB operations, and + * this filter is intentionally scoped to that third-party package so + * eval warnings from app code still surface. + */ + if (level === 'warn' && message.includes('Use of direct `eval`') && message.includes('@electric-sql/pglite')) { + return; + } + + if (level === 'warn' && message.includes('[PLUGIN_TIMINGS]')) { + return; + } + + defaultHandler(level, log); + } + } + }, test: { expect: { requireAssertions: true }, ui: false, -- 2.51.2