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
814 changes: 42 additions & 772 deletions package-lock.json

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@
"format:check": "prettier --check ."
},
"devDependencies": {
"@sveltejs/adapter-node": "^5.5.7",
"@sveltejs/kit": "^2.63.0",
"@sveltejs/adapter-node": "^6.0.0",
"@sveltejs/kit": "^3.0.0",
"@sveltejs/vite-plugin-svelte": "^7.1.2",
"@types/node": "^26.5.0",
"prettier": "^3.9.6",
"prettier-plugin-svelte": "^4.1.1",
"svelte": "^5.56.1",
"svelte-check": "^4.6.0",
"svelte": "^5.57.1",
"svelte-check": "^4.7.5",
"typescript": "^6.0.3",
"vite": "^8.0.16",
"vitest": "^5.0.0"
Expand Down Expand Up @@ -52,13 +52,13 @@
"LICENSE"
],
"engines": {
"node": "^22.12.0 || >=24.0.0"
"node": "^22.17.0 || >=24.0.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/NotAFlightRisk/ai-usage-dashboard.git"
},
"overrides": {
"cookie": "^0.7.0"
"imports": {
"#lib/*": "./src/lib/*"
}
}
6 changes: 3 additions & 3 deletions src/hooks.server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { boot } from '$lib/server/refresh';
import { settings } from '$lib/server/settings';
import type { Handle } from '@sveltejs/kit';
import type { Handle } from '@sveltejs/kit/hooks';
import { boot } from '#lib/server/refresh.js';
import { settings } from '#lib/server/settings.js';

boot();

Expand Down
4 changes: 2 additions & 2 deletions src/lib/components/BarList.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { tooltip } from '$lib/tooltip';
import Mark from '$lib/logos/Mark.svelte';
import { tooltip } from '#lib/tooltip.js';
import Mark from '#lib/logos/Mark.svelte';

type Row = {
id: string;
Expand Down
4 changes: 2 additions & 2 deletions src/lib/components/Calendar.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { tooltip } from '$lib/tooltip';
import { compact, dayLabel, money } from '$lib/format';
import { tooltip } from '#lib/tooltip.js';
import { compact, dayLabel, money } from '#lib/format.js';

type Day = { day: string; total: number; cost: number | null; events: number };

Expand Down
4 changes: 2 additions & 2 deletions src/lib/components/Clock.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { tooltip } from '$lib/tooltip';
import { compact } from '$lib/format';
import { tooltip } from '#lib/tooltip.js';
import { compact } from '#lib/format.js';

let { points }: { points: { day: number; hour: number; total: number }[] } = $props();

Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/Donut.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import { tooltip } from '$lib/tooltip';
import { tooltip } from '#lib/tooltip.js';

let {
slices,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/Fields.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import { tooltip } from '$lib/tooltip';
import { tooltip } from '#lib/tooltip.js';

let {
options,
Expand Down
6 changes: 3 additions & 3 deletions src/lib/components/Figures.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { tooltip } from '$lib/tooltip';
import { compact, delta, full, money } from '$lib/format';
import type { Slice } from '$lib/types';
import { tooltip } from '#lib/tooltip.js';
import { compact, delta, full, money } from '#lib/format.js';
import type { Slice } from '#lib/types.js';

let {
totals,
Expand Down
6 changes: 3 additions & 3 deletions src/lib/components/Meter.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { tooltip } from '$lib/tooltip';
import { relative } from '$lib/format';
import type { WindowRow } from '$lib/types';
import { tooltip } from '#lib/tooltip.js';
import { relative } from '#lib/format.js';
import type { WindowRow } from '#lib/types.js';

let { window: meter }: { window: WindowRow } = $props();

Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/Panel.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import type { Snippet } from 'svelte';
import { tooltip } from '$lib/tooltip';
import { tooltip } from '#lib/tooltip.js';

let {
title,
Expand Down
4 changes: 2 additions & 2 deletions src/lib/components/Problems.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { relative } from '$lib/format';
import type { Usage } from '$lib/types';
import { relative } from '#lib/format.js';
import type { Usage } from '#lib/types.js';

let { problems }: { problems: Usage['problems'] } = $props();

Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/Segmented.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts" generics="T extends string">
import { tooltip } from '$lib/tooltip';
import { tooltip } from '#lib/tooltip.js';

let {
options,
Expand Down
12 changes: 6 additions & 6 deletions src/lib/components/Sessions.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts" module>
import { clockLabel, compact, duration, modelName, money, percent } from '$lib/format';
import type { SessionRow } from '$lib/types';
import { clockLabel, compact, duration, modelName, money, percent } from '#lib/format.js';
import type { SessionRow } from '#lib/types.js';

type Column = {
id: string;
Expand Down Expand Up @@ -89,10 +89,10 @@
</script>

<script lang="ts">
import { tooltip } from '$lib/tooltip';
import Mark from '$lib/logos/Mark.svelte';
import { projectName } from '$lib/format';
import { toolMeta } from '$lib/providers';
import { tooltip } from '#lib/tooltip.js';
import Mark from '#lib/logos/Mark.svelte';
import { projectName } from '#lib/format.js';
import { toolMeta } from '#lib/providers.js';

let {
rows,
Expand Down
10 changes: 5 additions & 5 deletions src/lib/components/Settings.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script lang="ts">
import { RANGES } from '$lib/range';
import { relative } from '$lib/format';
import { RATES, type Rate } from '$lib/pricing';
import { THEMES, type Theme } from '$lib/themes';
import type { Usage } from '$lib/types';
import { RANGES } from '#lib/range.js';
import { relative } from '#lib/format.js';
import { RATES, type Rate } from '#lib/pricing.js';
import { THEMES, type Theme } from '#lib/themes.js';
import type { Usage } from '#lib/types.js';

type Saved = {
theme: Theme;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/Split.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import { tooltip } from '$lib/tooltip';
import { tooltip } from '#lib/tooltip.js';

let {
parts
Expand Down
6 changes: 3 additions & 3 deletions src/lib/components/Trend.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { tooltip } from '$lib/tooltip';
import { compact, dayLabel, money, moneyCompact } from '$lib/format';
import type { DayPoint } from '$lib/types';
import { tooltip } from '#lib/tooltip.js';
import { compact, dayLabel, money, moneyCompact } from '#lib/format.js';
import type { DayPoint } from '#lib/types.js';

let {
series,
Expand Down
8 changes: 4 additions & 4 deletions src/routes/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { filtersFrom } from '$lib/server/request';
import { usage } from '$lib/server/queries';
import { settings } from '$lib/server/settings';
import { config } from '$lib/server/config';
import { filtersFrom } from '#lib/server/request.js';
import { usage } from '#lib/server/queries.js';
import { settings } from '#lib/server/settings.js';
import { config } from '#lib/server/config.js';
import type { PageServerLoad } from './$types';

export const load: PageServerLoad = ({ url }) => ({
Expand Down
59 changes: 31 additions & 28 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
<script lang="ts">
import { untrack } from 'svelte';
import { replaceState } from '$app/navigation';
import Panel from '$lib/components/Panel.svelte';
import Segmented from '$lib/components/Segmented.svelte';
import MultiSelect from '$lib/components/MultiSelect.svelte';
import Figures from '$lib/components/Figures.svelte';
import Calendar from '$lib/components/Calendar.svelte';
import Trend from '$lib/components/Trend.svelte';
import BarList from '$lib/components/BarList.svelte';
import Donut from '$lib/components/Donut.svelte';
import Split from '$lib/components/Split.svelte';
import Clock from '$lib/components/Clock.svelte';
import Meter from '$lib/components/Meter.svelte';
import Sessions, { COLUMNS } from '$lib/components/Sessions.svelte';
import Fields from '$lib/components/Fields.svelte';
import Problems from '$lib/components/Problems.svelte';
import SettingsDialog from '$lib/components/Settings.svelte';
import Logo from '$lib/logos/Logo.svelte';
import Mark from '$lib/logos/Mark.svelte';
import { tooltip } from '$lib/tooltip';
import { RANGES, rangeLabel } from '$lib/range';
import { goto } from '$app/navigation';
import Panel from '#lib/components/Panel.svelte';
import Segmented from '#lib/components/Segmented.svelte';
import MultiSelect from '#lib/components/MultiSelect.svelte';
import Figures from '#lib/components/Figures.svelte';
import Calendar from '#lib/components/Calendar.svelte';
import Trend from '#lib/components/Trend.svelte';
import BarList from '#lib/components/BarList.svelte';
import Donut from '#lib/components/Donut.svelte';
import Split from '#lib/components/Split.svelte';
import Clock from '#lib/components/Clock.svelte';
import Meter from '#lib/components/Meter.svelte';
import Sessions, { COLUMNS } from '#lib/components/Sessions.svelte';
import Fields from '#lib/components/Fields.svelte';
import Problems from '#lib/components/Problems.svelte';
import SettingsDialog from '#lib/components/Settings.svelte';
import Logo from '#lib/logos/Logo.svelte';
import Mark from '#lib/logos/Mark.svelte';
import { tooltip } from '#lib/tooltip.js';
import { RANGES, rangeLabel } from '#lib/range.js';
import {
compact,
full,
Expand All @@ -28,9 +28,9 @@
moneyCompact,
projectName,
relative
} from '$lib/format';
import { providerFor, providerMeta, toolMeta } from '$lib/providers';
import type { Usage } from '$lib/types';
} from '#lib/format.js';
import { providerFor, providerMeta, toolMeta } from '#lib/providers.js';
import type { Usage } from '#lib/types.js';
import type { PageData } from './$types';

let { data }: { data: PageData } = $props();
Expand Down Expand Up @@ -78,7 +78,7 @@
$effect(() => {
if (query === showing) return;
showing = query;
replaceState(`?${query}`, {});
void goto(`?${query}`, { shallow: true, replace: true });
void pull(query);
});

Expand All @@ -92,19 +92,22 @@
document.documentElement.dataset.theme = theme === 'auto' ? '' : theme;
});

async function save(patch: Record<string, unknown>) {
const response = await fetch('/api/settings', {
const post = (path: string, body: Record<string, unknown> = {}) =>
fetch(path, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(patch)
body: JSON.stringify(body)
});

async function save(patch: Record<string, unknown>) {
const response = await post('/api/settings', patch);
if (response.ok) saved = await response.json();
}

async function rescan() {
busy = true;
try {
const response = await fetch(`/api/refresh?${showing}`, { method: 'POST' });
const response = await post(`/api/refresh?${showing}`);
if (response.ok) usage = await response.json();
} finally {
busy = false;
Expand Down
9 changes: 4 additions & 5 deletions src/routes/api/refresh/+server.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { json } from '@sveltejs/kit';
import { refresh } from '$lib/server/refresh';
import { filtersFrom } from '$lib/server/request';
import { usage } from '$lib/server/queries';
import { refresh } from '#lib/server/refresh.js';
import { filtersFrom } from '#lib/server/request.js';
import { usage } from '#lib/server/queries.js';
import type { RequestHandler } from './$types';

export const POST: RequestHandler = async ({ url }) => {
await refresh(true);
return json(usage(filtersFrom(url)));
return Response.json(usage(filtersFrom(url)));
};
11 changes: 5 additions & 6 deletions src/routes/api/settings/+server.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { json } from '@sveltejs/kit';
import { saveSettings, settings, type Settings } from '$lib/server/settings';
import { clearUsageMemo } from '$lib/server/queries';
import { refresh } from '$lib/server/refresh';
import { saveSettings, settings, type Settings } from '#lib/server/settings.js';
import { clearUsageMemo } from '#lib/server/queries.js';
import { refresh } from '#lib/server/refresh.js';
import type { RequestHandler } from './$types';

export const GET: RequestHandler = () => json(settings());
export const GET: RequestHandler = () => Response.json(settings());

export const POST: RequestHandler = async ({ request }) => {
const patch = (await request.json()) as Partial<Settings>;
const next = saveSettings(patch);
clearUsageMemo();
if (patch.claudeWindows || patch.prices) await refresh();
return json(next);
return Response.json(next);
};
7 changes: 3 additions & 4 deletions src/routes/api/usage/+server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { json } from '@sveltejs/kit';
import { filtersFrom } from '$lib/server/request';
import { usage } from '$lib/server/queries';
import { filtersFrom } from '#lib/server/request.js';
import { usage } from '#lib/server/queries.js';
import type { RequestHandler } from './$types';

export const GET: RequestHandler = ({ url }) => json(usage(filtersFrom(url)));
export const GET: RequestHandler = ({ url }) => Response.json(usage(filtersFrom(url)));
19 changes: 4 additions & 15 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,9 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"extends": "$app/tsconfig",
"compilerOptions": {
"rewriteRelativeImportExtensions": true,
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler"
}
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
//
// To make changes to top-level options such as include and exclude, we recommend extending
// the generated config; see https://svelte.dev/docs/kit/configuration#typescript
"strict": true
},
"include": ["src", "vite.config.ts", "tests"]
}
Loading