Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .cursor/rules/svelte.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ UI and Styling

- 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
Expand Down Expand Up @@ -106,8 +106,7 @@ SvelteKit Project Structure
- routes/
- app.html
- static/
- svelte.config.js
- vite.config.js
- vite.config.ts
```

Component Development
Expand Down
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ DEFAULT_DATASET=uoregon
# 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
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,6 @@ jobs:

- 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
Expand Down
2 changes: 1 addition & 1 deletion .node-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
22.16.0
24.4.1
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ ATLANTIS turns NetFlow captures and CSV imports into queryable aggregate databas
## 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.
Expand Down
4 changes: 3 additions & 1 deletion apps/web/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import js from '@eslint/js';
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,
Expand Down
30 changes: 19 additions & 11 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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": "^7.2.9",
"@sveltejs/kit": "^2.70.3",
"@sveltejs/vite-plugin-svelte": "^6.2.4",
"@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",
"@tailwindcss/vite": "^4.0.0",
"@types/better-sqlite3": "^7.6.13",
"@types/node": "^22.15.17",
Expand All @@ -55,19 +56,26 @@
"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",
"better-sqlite3": "^12.6.2",
"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"
}
}
}
6 changes: 3 additions & 3 deletions apps/web/playwright.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ export default defineConfig({
],
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: 120_000
timeout: 180_000
}
: undefined
});
11 changes: 0 additions & 11 deletions apps/web/src/app.d.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -8,15 +6,6 @@ declare global {
// interface Locals {}
// interface PageData {}
// interface PageState {}
interface Platform {
env: {
DB: D1Database;
};
context: {
waitUntil(promise: Promise<unknown>): void;
};
caches: CacheStorage & { default: Cache };
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions apps/web/src/cloudflare-workers.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare module 'cloudflare:workers' {
export const env: {
DB: import('@cloudflare/workers-types').D1Database;
};
}
18 changes: 18 additions & 0 deletions apps/web/src/env.ts
Original file line number Diff line number Diff line change
@@ -0,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
}
});
35 changes: 17 additions & 18 deletions apps/web/src/lib/components/charts/BreakdownChart.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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';
import { Skeleton } from '$lib/components/ui/skeleton';
import SegmentedControl from '$lib/components/common/SegmentedControl.svelte';
import { navigateToNetflowFile } from '$lib/utils/netflow-file-navigation';
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 { navigateToNetflowFile } from '#lib/utils/netflow-file-navigation.ts';
import {
DEFAULT_MAAD_IP_VERSION,
MAAD_IP_VERSION_OPTIONS,
Expand All @@ -23,9 +23,9 @@
type ProtocolMetricKey,
type SpectrumPoint,
type TimeBucket
} from '$lib/types/types';
import type { SpectrumStatsPayload } from '$lib/types/spectrum-stats';
import type { DimensionMetricKey } from '$lib/types/dimension-stats';
} from '#lib/types/types.ts';
import type { SpectrumStatsPayload } from '#lib/types/spectrum-stats.ts';
import type { DimensionMetricKey } from '#lib/types/dimension-stats.ts';
import {
BREAKDOWN_CHART_CONFIGS,
DIMENSION_ORDER_OPTIONS,
Expand Down Expand Up @@ -66,17 +66,17 @@
shouldHighlightIpGranularityGrid,
placeTicksOnBucketStarts
} from './ip-time-axis';
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 { 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 {
ensureCachedWindow,
getMissingWindowRanges,
readCachedWindow,
type TimeRange
} from '$lib/utils/window-cache';
} from '#lib/utils/window-cache.ts';

const IP_TO_GROUP_BY: Record<IpGranularity, GroupByOption> = {
'1d': 'date',
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
});
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/lib/components/charts/ChartCard.svelte
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
14 changes: 7 additions & 7 deletions apps/web/src/lib/components/charts/ChartContainer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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 { rangeSelection } from '$lib/stores/rangeSelection.svelte';
import { theme } from '$lib/stores/theme.svelte';
import { cancelDrawFrame, requestDrawFrame } from '$lib/utils/animation-frame';
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 { 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,
Expand All @@ -36,7 +36,7 @@
epochToPSTComponents,
getWeekdayName,
type PSTDateComponents
} from '$lib/utils/timezone';
} from '#lib/utils/timezone.ts';
import type {
NetflowDataPoint,
GroupByOption,
Expand All @@ -45,7 +45,7 @@
ClickedElement,
ChartConfig,
ChartDataset
} from '$lib/components/netflow/types.ts';
} from '#lib/components/netflow/types.ts';

interface Props {
results: NetflowDataPoint[];
Expand Down
16 changes: 8 additions & 8 deletions apps/web/src/lib/components/charts/CoverageStrip.svelte
Original file line number Diff line number Diff line change
@@ -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 = {
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
14 changes: 7 additions & 7 deletions apps/web/src/lib/components/charts/MetricLinePanel.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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 { cancelDrawFrame, requestDrawFrame } from '$lib/utils/animation-frame';
import { formatDateAsPSTDateString } from '$lib/utils/timezone';
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 { formatDateAsPSTDateString } from '#lib/utils/timezone.ts';
import {
MIN_DRAG_PIXELS,
Y_AXIS_WIDTH,
Expand Down
Loading
Loading