# Files changed · PR \#115 · flambo/atlantis

[View on GitCafe](https://git.cafe/flambo/atlantis/pull/115/diffs)

Repository: [flambo/atlantis](https://git.cafe/flambo/atlantis)

Visibility: public

[feat\(web\)\!: migrate to SvelteKit 3 and Vite 8 with build-time DB driver](https://git.cafe/flambo/atlantis/pull/115.md)

Version: 0

Head commit: b72af5856c99a520a25c9c1a604dbd39e56a4153

Base commit: e9dbda72d5a0ec91b924442722dbcbb5cfbef703

Comparison base: e9dbda72d5a0ec91b924442722dbcbb5cfbef703

Showing up to 20 entries from this revision. If the pull request changes, reopen the first page before continuing.

## \.cursor/rules/svelte.mdc

Status: modified; +3; −4

````diff
@@ -67,8 +67,8 @@
 
 - Use Tailwind CSS for utility-first styling approach.
 - Leverage Shadcn components for pre-built, customizable UI elements.
-- Import Shadcn components from `$lib/components/ui`.
-- Organize Tailwind classes using the `cn()` utility from `$lib/utils`.
+- Import Shadcn components from `#lib/components/ui/<component>/index.ts`.
+- Organize Tailwind classes using the `cn()` utility from `#lib/utils.ts`.
 - Use Svelte's built-in transition and animation features.
 
 Shadcn Color Conventions
@@ -106,8 +106,7 @@
     - routes/
     - app.html
   - static/
-  - svelte.config.js
+  - vite.config.ts
-  - vite.config.js
   ```
 
 Component Development
````

## \.env.example

Status: modified; +2; −2

```diff
@@ -8,8 +8,8 @@
 # The dataset registry can be at a different location.
 # DATASETS_CONFIG_PATH=./datasets.json
 
-# The local web application reads SQLite by default.
-ATLANTIS_DB_DRIVER=sqlite
+# ATLANTIS_DB_DRIVER selects the web database driver when the dashboard starts or builds.
+# Set it in the shell, not in this file. See docs/code/development.md.
 
 # Set one database path or use automatic discovery at data/*/netflow.sqlite.
 # LOCAL_SQLITE_PATH=/absolute/path/to/netflow.sqlite
```

## \.github/workflows/ci.yaml

Status: modified; +0; −2

```diff
@@ -116,8 +116,6 @@
 
       - run: bun install --frozen-lockfile
 
-      - run: bun run build:web
-
       - run: cd apps/web && bunx playwright install --with-deps chromium
 
       - run: cd apps/web && PLAYWRIGHT_WEB_SERVER=1 bun run test:e2e
```

## \.node-version

Status: modified; +1; −1

```diff
@@ -1,1 +1,1 @@
-22.16.0
+24.4.1
```

## AGENTS.md

Status: modified; +1; −1

```diff
@@ -5,7 +5,7 @@
 ## Repository Map
 
 - `tools/netflow-db`: Rust pipeline (`atlantis-netflow-db` crate) for ingestion, aggregation, verification, and analysis-window exports. Native `nfcapd` ingestion uses the pinned `nfdump` fork in `vendor/nfdump`.
-- `apps/web`: Svelte 5/SvelteKit 2 dashboard and API routes. It reads local SQLite during development and Cloudflare D1 in deployment.
+- `apps/web`: Svelte 5/SvelteKit 3 dashboard and API routes. It reads local SQLite during development and Cloudflare D1 in deployment.
 - `apps/landing`: Astro marketing and SEO site.
 - `vendor/*`: Third-party analysis submodules. Treat these as read-only; build repo-local binaries through the scripts in `vendor/scripts/`.
 - `data/`, `.env`, and `datasets.json`: Machine-local inputs and generated databases. Keep paths and dataset contents out of commits.
```

## apps/web/eslint.config.js

Status: modified; +3; −1

```diff
@@ -3,8 +3,10 @@
 import svelte from 'eslint-plugin-svelte';
 import globals from 'globals';
 import ts from 'typescript-eslint';
-import svelteConfig from './svelte.config.js';
+import { loadConfig } from '@sveltejs/load-config';
 
+const svelteConfig = (await loadConfig('./', { traverse: false }))?.config;
+
 export default ts.config(
 	js.configs.recommended,
 	...ts.configs.recommended,
```

## apps/web/package.json

Status: modified; +19; −11

```diff
@@ -8,7 +8,7 @@
 		"build": "vite build",
 		"deploy": "wrangler deploy",
 		"deploy:dry-run": "wrangler deploy --dry-run",
-		"preview": "vite preview",
+		"preview": "ATLANTIS_DB_DRIVER=sqlite vite build && vite preview",
 		"playwright": "bunx playwright test",
 		"prepare": "svelte-kit sync || echo ''",
 		"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
@@ -28,14 +28,15 @@
 		"d1:execute": "wrangler d1 execute atlantis-db"
 	},
 	"devDependencies": {
-		"@cloudflare/workers-types": "^4.20260511.1",
+		"@cloudflare/workers-types": "^5.20260924.1",
 		"@eslint/compat": "^1.2.5",
 		"@eslint/js": "^9.18.0",
 		"@internationalized/date": "^3.12.0",
 		"@playwright/test": "1.52.0",
+		"@sveltejs/adapter-cloudflare": "8.0.0-next.7",
+		"@sveltejs/kit": "3.0.0-next.27",
+		"@sveltejs/load-config": "^0.2.3",
+		"@sveltejs/vite-plugin-svelte": "^7.3.1",
-		"@sveltejs/adapter-cloudflare": "^7.2.9",
-		"@sveltejs/kit": "^2.70.3",
-		"@sveltejs/vite-plugin-svelte": "^6.2.4",
 		"@tailwindcss/vite": "^4.0.0",
 		"@types/better-sqlite3": "^7.6.13",
 		"@types/node": "^22.15.17",
@@ -55,11 +56,11 @@
 		"tailwind-variants": "^3.3.1",
 		"tailwindcss": "^4.0.0",
 		"tw-animate-css": "^1.4.0",
-		"typescript": "^5.0.0",
-		"typescript-eslint": "^8.20.0",
-		"vite": "^7.3.6",
-		"vitest": "^3.2.7",
-		"wrangler": "^4.90.0"
+		"typescript": "^6.0.3",
+		"typescript-eslint": "^8.70.1",
+		"vite": "^8.3.0",
+		"vitest": "^5.0.1",
+		"wrangler": "^4.137.0"
 	},
 	"dependencies": {
 		"@lucide/svelte": "^1.33.0",
@@ -67,7 +68,14 @@
 		"chart.js": "^4.4.9",
 		"chartjs-plugin-annotation": "^3.1.0",
 		"drizzle-orm": "^0.45.2",
-		"runed": "^0.36.0",
 		"zod": "^4.3.6"
+	},
+	"imports": {
+		"#lib": "./src/lib/index.ts",
+		"#lib/*": "./src/lib/*",
+		"#db": {
+			"atlantis-d1": "./src/lib/server/db/d1.ts",
+			"default": "./src/lib/server/db/sqlite.ts"
+		}
 	}
 }
```

## apps/web/playwright.config.js

Status: modified; +3; −3

```diff
@@ -37,15 +37,15 @@
 	],
 	webServer: shouldManageServer
 		? {
-				command: 'bun run preview --host 127.0.0.1 --port 4173',
+				command: 'bun run build && bun run preview --host 127.0.0.1 --port 4173',
 				env: {
 					...process.env,
-					ATLANTIS_DB_DRIVER: 'sqlite',
+					ATLANTIS_DB_DRIVER: 'd1',
 					LOCAL_SQLITE_PATH: playwrightFixture?.databasePath
 				},
 				port: 4173,
 				reuseExistingServer: false,
+				timeout: 180_000
-				timeout: 120_000
 			}
 		: undefined
 });
```

## apps/web/src/app.d.ts

Status: modified; +0; −11

```diff
@@ -1,5 +1,3 @@
-import type { D1Database } from '@cloudflare/workers-types';
-
 // See https://svelte.dev/docs/kit/types#app.d.ts
 // for information about these interfaces
 declare global {
@@ -8,15 +6,6 @@
 		// interface Locals {}
 		// interface PageData {}
 		// interface PageState {}
-		interface Platform {
-			env: {
-				DB: D1Database;
-			};
-			context: {
-				waitUntil(promise: Promise<unknown>): void;
-			};
-			caches: CacheStorage & { default: Cache };
-		}
 	}
 }
 
```

## apps/web/src/cloudflare-workers.d.ts

Status: added; +5; −0

```diff
@@ -1,0 +1,5 @@
+declare module 'cloudflare:workers' {
+	export const env: {
+		DB: import('@cloudflare/workers-types').D1Database;
+	};
+}
```

## apps/web/src/env.ts

Status: added; +18; −0

```diff
@@ -1,0 +1,18 @@
+import { defineEnvVars } from '@sveltejs/kit/env';
+
+const optional = (value: string | undefined) => value?.trim() || undefined;
+
+export const variables = defineEnvVars({
+	LOCAL_SQLITE_PATH: {
+		description: 'Path to a single pipeline SQLite product; disables data/ discovery when set',
+		schema: optional
+	},
+	DATABASE_PATH: {
+		description: 'Fallback for LOCAL_SQLITE_PATH',
+		schema: optional
+	},
+	DEFAULT_DATASET: {
+		description: 'Dataset ID selected when a request does not name one',
+		schema: optional
+	}
+});
```

## apps/web/src/lib/components/charts/BreakdownChart.svelte

Status: modified; +17; −18

```diff
@@ -5,12 +5,12 @@
 	import { buildCoveragePointStyle } from './coverage-line-style';
 	import { getRelativePosition } from 'chart.js/helpers';
 	import type { ActiveElement, ChartEvent } from 'chart.js';
-	import type { GroupByOption, RouterConfig } from '$lib/components/netflow/types.ts';
+	import type { GroupByOption, RouterConfig } from '#lib/components/netflow/types.ts';
 	import ChartCard from './ChartCard.svelte';
+	import { Checkbox } from '#lib/components/ui/checkbox/index.ts';
+	import { Skeleton } from '#lib/components/ui/skeleton/index.ts';
+	import SegmentedControl from '#lib/components/common/SegmentedControl.svelte';
-	import { Checkbox } from '$lib/components/ui/checkbox';
-	import { Skeleton } from '$lib/components/ui/skeleton';
-	import SegmentedControl from '$lib/components/common/SegmentedControl.svelte';
-	import { navigateToNetflowFile } from '$lib/utils/netflow-file-navigation';
+	import { navigateToNetflowFile } from '#lib/utils/netflow-file-navigation.ts';
 	import {
 		DEFAULT_MAAD_IP_VERSION,
 		MAAD_IP_VERSION_OPTIONS,
@@ -23,9 +23,9 @@
 		type ProtocolMetricKey,
 		type SpectrumPoint,
 		type TimeBucket
+	} from '#lib/types/types.ts';
+	import type { SpectrumStatsPayload } from '#lib/types/spectrum-stats.ts';
-	} from '$lib/types/types';
+	import type { DimensionMetricKey } from '#lib/types/dimension-stats.ts';
-	import type { SpectrumStatsPayload } from '$lib/types/spectrum-stats';
-	import type { DimensionMetricKey } from '$lib/types/dimension-stats';
 	import {
 		BREAKDOWN_CHART_CONFIGS,
 		DIMENSION_ORDER_OPTIONS,
@@ -66,17 +66,17 @@
 		shouldHighlightIpGranularityGrid,
 		placeTicksOnBucketStarts
 	} from './ip-time-axis';
+	import { dateStringToEpochPST, formatDateAsPSTDateString } from '#lib/utils/timezone.ts';
+	import { crosshairStore } from '#lib/stores/crosshair.ts';
+	import { rangeSelection } from '#lib/stores/rangeSelection.svelte.ts';
+	import { theme } from '#lib/stores/theme.svelte.ts';
+	import { cancelDrawFrame, requestDrawFrame } from '#lib/utils/animation-frame.ts';
-	import { dateStringToEpochPST, formatDateAsPSTDateString } from '$lib/utils/timezone';
-	import { crosshairStore } from '$lib/stores/crosshair';
-	import { rangeSelection } from '$lib/stores/rangeSelection.svelte';
-	import { theme } from '$lib/stores/theme.svelte';
-	import { cancelDrawFrame, requestDrawFrame } from '$lib/utils/animation-frame';
 	import {
 		ensureCachedWindow,
 		getMissingWindowRanges,
 		readCachedWindow,
 		type TimeRange
+	} from '#lib/utils/window-cache.ts';
-	} from '$lib/utils/window-cache';
 
 	const IP_TO_GROUP_BY: Record<IpGranularity, GroupByOption> = {
 		'1d': 'date',
@@ -117,8 +117,7 @@
 		routers?: RouterConfig;
 		activeMetrics?: MetricsForKind<Kind>;
 		direction?: FlowDirection;
-		onDateChange?: (payload: { startDate: string; endDate: string }) => void;
-		onGroupByChange?: (payload: { groupBy: GroupByOption }) => void;
+		onDrillDown?: (payload: { groupBy: GroupByOption; startDate: string; endDate: string }) => void;
 		onRouterChange?: (payload: { router: string }) => void;
 		onAddressTypeChange?: (payload: { addressType: 'sa' | 'da' }) => void;
 		onMetricsChange?: (payload: { metrics: MetricsForKind<Kind> }) => void;
@@ -507,8 +506,8 @@
 	}
 
 	function emitDrilldown(nextGroupBy: GroupByOption, start: Date, end: Date) {
-		props.onGroupByChange?.({ groupBy: nextGroupBy });
-		props.onDateChange?.({
+		props.onDrillDown?.({
+			groupBy: nextGroupBy,
 			startDate: formatDate(start),
 			endDate: formatDate(end)
 		});
```

## apps/web/src/lib/components/charts/ChartCard.svelte

Status: modified; +2; −2

```diff
@@ -1,6 +1,6 @@
 <script lang="ts">
-	import DragGrip from '$lib/components/common/DragGrip.svelte';
-	import * as Card from '$lib/components/ui/card';
+	import DragGrip from '#lib/components/common/DragGrip.svelte';
+	import * as Card from '#lib/components/ui/card/index.ts';
 	import type { Snippet } from 'svelte';
 
 	let {
```

## apps/web/src/lib/components/charts/ChartContainer.svelte

Status: modified; +7; −7

```diff
@@ -6,12 +6,12 @@
 	import { resolve } from '$app/paths';
 	import { Chart } from './chart-registry';
 	import { buildCoveragePointStyle } from './coverage-line-style';
-	import { crosshairStore } from '$lib/stores/crosshair';
+	import { crosshairStore } from '#lib/stores/crosshair.ts';
+	import { rangeSelection } from '#lib/stores/rangeSelection.svelte.ts';
+	import { theme } from '#lib/stores/theme.svelte.ts';
-	import { rangeSelection } from '$lib/stores/rangeSelection.svelte';
-	import { theme } from '$lib/stores/theme.svelte';
-	import { cancelDrawFrame, requestDrawFrame } from '$lib/utils/animation-frame';
+	import { cancelDrawFrame, requestDrawFrame } from '#lib/utils/animation-frame.ts';
 	import { SvelteSet } from 'svelte/reactivity';
-	import { NETFLOW_DATA_OPTION_FIELDS } from '$lib/components/netflow/constants';
+	import { NETFLOW_DATA_OPTION_FIELDS } from '#lib/components/netflow/constants.ts';
 	import {
 		formatLabels,
 		getXAxisTitle,
@@ -36,7 +36,7 @@
 		epochToPSTComponents,
 		getWeekdayName,
 		type PSTDateComponents
+	} from '#lib/utils/timezone.ts';
-	} from '$lib/utils/timezone';
 	import type {
 		NetflowDataPoint,
 		GroupByOption,
@@ -45,7 +45,7 @@
 		ClickedElement,
 		ChartConfig,
 		ChartDataset
+	} from '#lib/components/netflow/types.ts';
-	} from '$lib/components/netflow/types.ts';
 
 	interface Props {
 		results: NetflowDataPoint[];
```

## apps/web/src/lib/components/charts/CoverageStrip.svelte

Status: modified; +8; −8

```diff
@@ -1,5 +1,5 @@
 <script module lang="ts">
-	import type { CoverageTimeline, CoverageTimelineBucket } from '$lib/types/types';
+	import type { CoverageTimeline, CoverageTimelineBucket } from '#lib/types/types.ts';
 	import { SvelteMap } from 'svelte/reactivity';
 
 	export type CachedCoverageRecord = {
@@ -35,18 +35,18 @@
 <script lang="ts">
 	import { onDestroy } from 'svelte';
 	import type { Plugin, TooltipItem } from 'chart.js';
-	import DragGrip from '$lib/components/common/DragGrip.svelte';
-	import type { BucketCoverage, CoverageState } from '$lib/types/types';
-	import type { GroupByOption, RouterConfig } from '$lib/components/netflow/types';
-	import { dateStringToEpochPST } from '$lib/utils/timezone';
+	import DragGrip from '#lib/components/common/DragGrip.svelte';
+	import type { BucketCoverage, CoverageState } from '#lib/types/types.ts';
+	import type { GroupByOption, RouterConfig } from '#lib/components/netflow/types.ts';
+	import { dateStringToEpochPST } from '#lib/utils/timezone.ts';
 	import {
 		ensureCachedWindow,
 		getMissingWindowRanges,
 		readCachedWindow,
 		type TimeRange
-	} from '$lib/utils/window-cache';
-	import { crosshairStore } from '$lib/stores/crosshair';
-	import { theme } from '$lib/stores/theme.svelte';
+	} from '#lib/utils/window-cache.ts';
+	import { crosshairStore } from '#lib/stores/crosshair.ts';
+	import { theme } from '#lib/stores/theme.svelte.ts';
 	import { Chart } from './chart-registry';
 	import { findTemporalDataBounds } from './chart-utils';
 	import {
```

## apps/web/src/lib/components/charts/FlowCharacteristicsChart.svelte

Status: modified; +2; −2

```diff
@@ -2,13 +2,13 @@
 	import ChartCard from './ChartCard.svelte';
 	import MetricLinePanel, { type MetricLineSeries } from './MetricLinePanel.svelte';
 	import { indexObservationBuckets, type IndexedObservationBucket } from './flow-characteristics';
-	import type { GroupByOption } from '$lib/components/netflow/types';
+	import type { GroupByOption } from '#lib/components/netflow/types.ts';
 	import type {
 		BucketCoverage,
 		FlowCharacteristicsResponse,
 		IpGranularity,
 		NetflowIpFamily
-	} from '$lib/types/types';
+	} from '#lib/types/types.ts';
 
 	type Props = {
 		data: FlowCharacteristicsResponse | null;
```

## apps/web/src/lib/components/charts/MetricLinePanel.svelte

Status: modified; +7; −7

```diff
@@ -8,18 +8,18 @@
 	} from 'chart.js';
 	import { Chart } from './chart-registry';
 	import { buildCoveragePointStyle } from './coverage-line-style';
-	import type { GroupByOption } from '$lib/components/netflow/types';
-	import type { IpGranularity } from '$lib/types/types';
+	import type { GroupByOption } from '#lib/components/netflow/types.ts';
+	import type { IpGranularity } from '#lib/types/types.ts';
 	import {
 		formatIpGranularityTick,
 		formatTemporalBucketLabel,
 		shouldHighlightIpGranularityGrid
 	} from './ip-time-axis';
-	import { theme } from '$lib/stores/theme.svelte';
-	import { crosshairStore } from '$lib/stores/crosshair';
-	import { rangeSelection } from '$lib/stores/rangeSelection.svelte';
+	import { theme } from '#lib/stores/theme.svelte.ts';
+	import { crosshairStore } from '#lib/stores/crosshair.ts';
+	import { rangeSelection } from '#lib/stores/rangeSelection.svelte.ts';
+	import { cancelDrawFrame, requestDrawFrame } from '#lib/utils/animation-frame.ts';
-	import { cancelDrawFrame, requestDrawFrame } from '$lib/utils/animation-frame';
+	import { formatDateAsPSTDateString } from '#lib/utils/timezone.ts';
-	import { formatDateAsPSTDateString } from '$lib/utils/timezone';
 	import {
 		MIN_DRAG_PIXELS,
 		Y_AXIS_WIDTH,
```

## apps/web/src/lib/components/charts/PortCardinalityChart.svelte

Status: modified; +3; −3

```diff
@@ -1,6 +1,6 @@
 <script lang="ts">
 	import { SvelteSet } from 'svelte/reactivity';
-	import { Checkbox } from '$lib/components/ui/checkbox';
+	import { Checkbox } from '#lib/components/ui/checkbox/index.ts';
 	import ChartCard from './ChartCard.svelte';
 	import MetricLinePanel, { type MetricLineSeries } from './MetricLinePanel.svelte';
 	import {
@@ -8,14 +8,14 @@
 		indexPortTimelines,
 		type IndexedPortBucket
 	} from './flow-characteristics';
-	import type { GroupByOption } from '$lib/components/netflow/types';
+	import type { GroupByOption } from '#lib/components/netflow/types.ts';
 	import type {
 		FlowCharacteristicsResponse,
 		IpGranularity,
 		NetflowIpFamily,
 		PortRange,
 		PortSide
+	} from '#lib/types/types.ts';
-	} from '$lib/types/types';
 
 	type Props = {
 		data: FlowCharacteristicsResponse | null;
```

## apps/web/src/lib/components/charts/SpectrumChart.svelte

Status: modified; +2; −2

```diff
@@ -1,8 +1,8 @@
 <script lang="ts">
 	import { onMount } from 'svelte';
 	import { Chart } from './annotation-chart-registry';
-	import type { SpectrumData } from '$lib/types/types';
-	import { theme } from '$lib/stores/theme.svelte';
+	import type { SpectrumData } from '#lib/types/types.ts';
+	import { theme } from '#lib/stores/theme.svelte.ts';
 
 	let { data }: { data: SpectrumData } = $props();
 	let chartCanvas: HTMLCanvasElement;
```

## apps/web/src/lib/components/charts/StructureFunctionChart.svelte

Status: modified; +2; −2

```diff
@@ -1,8 +1,8 @@
 <script lang="ts">
 	import { onMount } from 'svelte';
 	import { Chart } from './annotation-chart-registry';
-	import type { StructureFunctionData } from '$lib/types/types';
-	import { theme } from '$lib/stores/theme.svelte';
+	import type { StructureFunctionData } from '#lib/types/types.ts';
+	import { theme } from '#lib/stores/theme.svelte.ts';
 
 	let { data }: { data: StructureFunctionData } = $props();
 	let chartCanvas: HTMLCanvasElement;
```

[Next page](https://git.cafe/flambo/atlantis/pull/115/diffs?after=ImFwcHMvd2ViL3NyYy9saWIvY29tcG9uZW50cy9jaGFydHMvU3RydWN0dXJlRnVuY3Rpb25DaGFydC5zdmVsdGUi&expectedVersion=0&format=markdown)
