Skip to content
Open
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
2 changes: 1 addition & 1 deletion .node-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
24.21.0
24.22.1
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
24.21.0
24.22.1
22,997 changes: 11,597 additions & 11,400 deletions package-lock.json

Large diffs are not rendered by default.

111 changes: 55 additions & 56 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,95 +29,94 @@
"db:studio": "drizzle-kit studio"
},
"devDependencies": {
"@cyclonedx/cyclonedx-npm": "^6.0.0",
"@eslint/compat": "^2.0.2",
"@cyclonedx/cyclonedx-npm": "^6.0.1",
"@eslint/compat": "^2.1.1",
"@eslint/js": "^9.39.2",
"@faker-js/faker": "^10.4.0",
"@faker-js/faker": "^10.6.0",
"@iconify-json/lsicon": "^1.2.5",
"@iconify-json/material-icon-theme": "^1.2.67",
"@iconify-json/material-symbols": "^1.2.74",
"@iconify-json/vscode-icons": "^1.2.55",
"@inlang/paraglide-js": "^2.12.0",
"@iconify-json/material-icon-theme": "^1.2.72",
"@iconify-json/material-symbols": "^1.2.95",
"@iconify-json/vscode-icons": "^1.2.91",
"@inlang/paraglide-js": "^2.29.0",
"@playwright/test": "1.61.1",
"@sveltejs/adapter-node": "^5.5.3",
"@sveltejs/adapter-node": "^5.5.7",
"@sveltejs/enhanced-img": "^0.11.0",
"@sveltejs/kit": "^2.53.0",
"@sveltejs/kit": "^2.70.3",
"@sveltejs/vite-plugin-svelte": "^6.2.4",
"@tailwindcss/vite": "^4.2.1",
"@testcontainers/postgresql": "^12.0.1",
"@types/node": "^24",
"@tailwindcss/vite": "^4.3.3",
"@testcontainers/postgresql": "^12.2.1",
"@types/node": "^24.19.2",
"@types/papaparse": "^5.5.2",
"@types/pg": "^8.20.0",
"@types/tar-stream": "^3.1.4",
"@types/pg": "^8.23.1",
"@vitest/browser-playwright": "^4.1.11",
"@vitest/coverage-v8": "^4.1.11",
"antlr-ng": "^1.0.10",
"archunit": "^2.3.3",
"daisyui": "^5.5.19",
"archunit": "^2.5.4",
"daisyui": "^5.7.50",
"devalue": "^5.9.4",
"drizzle-kit": "^0.31.10",
"eslint": "^9.39.2",
"drizzle-kit": "^0.31.11",
"eslint": "^9.39.5",
"eslint-config-prettier": "^10.1.8",
"eslint-import-resolver-typescript": "^4.4.5",
"eslint-plugin-better-tailwindcss": "^4.3.0",
"eslint-plugin-better-tailwindcss": "^4.9.1",
"eslint-plugin-check-file": "^3.3.2",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-security": "^4.0.0",
"eslint-plugin-svelte": "^3.15.0",
"globals": "^16.5.0",
"knip": "^6.37.0",
"oauth2-mock-server": "^8.2.2",
"pino-pretty": "^13.1.3",
"prettier": "^3.8.1",
"prettier-plugin-svelte": "^3.5.0",
"prettier-plugin-tailwindcss": "^0.7.2",
"svelte": "^5.53.3",
"svelte-check": "^4.4.3",
"sveltekit-superforms": "^2.30.0",
"eslint-plugin-security": "^4.2.0",
"eslint-plugin-svelte": "^3.23.1",
"globals": "^17.13.0",
"knip": "^6.42.0",
"oauth2-mock-server": "^9.3.0",
"pino-pretty": "^13.2.0",
"prettier": "^3.9.10",
"prettier-plugin-svelte": "^3.5.2",
"prettier-plugin-tailwindcss": "^0.8.1",
"svelte": "^5.57.2",
"svelte-check": "^4.7.7",
"sveltekit-superforms": "^2.31.0",
"tailwindcss": "^4.2.1",
"testcontainers": "^12.0.1",
"tsx": "^4.23.13",
"typescript": "^5.9.3",
"typescript-eslint": "^8.56.1",
"testcontainers": "^12.2.1",
"tsx": "^4.23.15",
"typescript": "^6.0.3",
"typescript-eslint": "^8.71.2",
"unplugin-icons": "^23.0.1",
"vite": "^7.3.1",
"vite": "^7.3.7",
"vitest": "^4.1.11",
"vitest-browser-svelte": "^2.0.2",
"zod": "^4.3.6"
"vitest-browser-svelte": "^2.2.1",
"zod": "^4.6.7"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.1041.0",
"@aws-sdk/lib-storage": "^3.1045.0",
"@better-auth/drizzle-adapter": "^1.6.20",
"@aws-sdk/client-s3": "^3.1152.0",
"@aws-sdk/lib-storage": "^3.1152.0",
"@better-auth/drizzle-adapter": "~1.6.33",
"@eslint-community/regexpp": "^4.12.2",
"@internationalized/date": "^3.11.0",
"@smithy/node-http-handler": "4.9.1",
"@internationalized/date": "^3.12.4",
"@smithy/node-http-handler": "^4.12.1",
"adm-zip": "^0.6.1",
"antlr4-c3": "^3.4.4",
"antlr4ng": "^3.0.16",
"better-auth": "^1.6.33",
"drizzle-orm": "^0.45.2",
"hyparquet": "^1.25.8",
"hyparquet-compressors": "^1.1.1",
"monaco-editor": "^0.55.1",
"papaparse": "^5.5.3",
"pg": "^8.21.0",
"pino": "^10.3.1",
"pretty-bytes": "^7.1.0",
"better-auth": "~1.6.33",
"drizzle-orm": "^0.45.4",
"hyparquet": "^1.31.5",
"hyparquet-compressors": "^1.1.2",
"monaco-editor": "^0.57.0",
"papaparse": "^5.7.0",
"pg": "^8.23.1",
"pino": "^10.4.0",
"pretty-bytes": "^7.2.0",
"prom-client": "^15.1.3",
"tar-stream": "^3.2.0",
"undici": "^7.24.4"
"tar-stream": "^3.2.2",
"undici": "^7.30.1"
},
"//overrides": {
"@sveltejs/kit > cookie": "SvelteKit requests ^0.6.0, which excludes the cookie validation security fix in 0.7.x. Remove when SvelteKit requires a patched version.",
"monaco-editor > dompurify": "Monaco pins DOMPurify to 3.2.7. Use ^3.4.16 for subsequent sanitisation security fixes; remove when Monaco requires an equally patched or newer version."
"monaco-editor > dompurify": "Monaco pins DOMPurify to 3.4.15. Use ^3.4.17 for subsequent sanitisation security fixes; remove when Monaco requires an equally patched or newer version."
},
"overrides": {
"@sveltejs/kit": {
"cookie": "^0.7.2"
},
"monaco-editor": {
"dompurify": "^3.4.16"
"dompurify": "^3.4.17"
}
}
}
5 changes: 2 additions & 3 deletions src/lib/components/editor/MonacoEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@

// Start loading in parallel with the rest of the page — not deferred to onMount.
// Guarded by `browser` because SvelteKit evaluates component scripts on the server too.
const workerImport = browser ? import('monaco-editor/esm/vs/editor/editor.worker?worker') : null;
const workerImport = browser ? import('monaco-editor/editor/editor.worker?worker') : null;
// The Trino SQL language pulls in the ANTLR parser (~1 MB); load it lazily alongside Monaco.
// It has no runtime dependency on monaco-editor, so starting it early does not
// load Monaco before the locale's NLS bundle below.
Expand All @@ -149,8 +149,7 @@
// Load Monaco's NLS bundle for the active locale. Static import strings are
// required — Vite cannot bundle bare-specifier template literals at build time.
if (getLocale() === 'de') {
// @ts-expect-error — Monaco ESM nls bundle has no types
await import('monaco-editor/esm/nls.messages.de.js');
await import('monaco-editor/nls/lang/de.js');
}

// By the time onMount fires the imports are likely already resolved.
Expand Down
5 changes: 2 additions & 3 deletions src/lib/components/editor/TextEditor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@
return extLanguageMap[extension] ?? 'plaintext';
});

const workerImport = browser ? import('monaco-editor/esm/vs/editor/editor.worker?worker') : null;
const workerImport = browser ? import('monaco-editor/editor/editor.worker?worker') : null;

function toMonacoTheme(t: string): string {
return t === 'dark' ? 'vs-dark' : 'vs';
Expand All @@ -156,8 +156,7 @@
// Load Monaco's NLS bundle for the active locale. Static import strings are
// required — Vite cannot bundle bare-specifier template literals at build time.
if (getLocale() === 'de') {
// @ts-expect-error — Monaco ESM nls bundle has no types
await import('monaco-editor/esm/nls.messages.de.js');
await import('monaco-editor/nls/lang/de.js');
}

const EditorWorker = (await workerImport!).default;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/editor/TextEditor.svelte.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { getLocale, setLocale } from '$lib/paraglide/runtime.js';
// TextEditor registers its save action, not Monaco itself.
const addAction = vi.hoisted(() => vi.fn());

vi.mock('monaco-editor/esm/vs/editor/editor.worker?worker', () => ({
vi.mock('monaco-editor/editor/editor.worker?worker', () => ({
default: class {}
}));

Expand Down
126 changes: 58 additions & 68 deletions src/lib/server/storage/archive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,8 +527,8 @@ interface TarListState {
}

function onTarEntry(
header: tar.Headers,
stream: NodeJS.ReadableStream,
header: tar.Header,
stream: tar.ExtractEvents['entry'][1],
next: (err?: Error | null) => void,
prefix: string,
state: TarListState,
Expand Down Expand Up @@ -623,12 +623,9 @@ function listTar(

const extract = tar.extract();

extract.on(
'entry',
(header: tar.Headers, stream: NodeJS.ReadableStream, next: (err?: Error | null) => void) => {
onTarEntry(header, stream, next, prefix, state, maxBytes);
}
);
extract.on('entry', (header, stream, next) => {
onTarEntry(header, stream, next, prefix, state, maxBytes);
});

extract.on('finish', () => {
if (state.tooLarge) {
Expand All @@ -655,37 +652,35 @@ function extractTarEntry(

const extract = tar.extract();

extract.on(
'entry',
(header: tar.Headers, stream: NodeJS.ReadableStream, next: (err?: Error | null) => void) => {
const entryPath = normalizePath(header.name);
if (header.type === 'file' && entryPath === normalized && !found) {
if (maxBytes !== undefined && (header.size ?? 0) > maxBytes) {
stream.resume();
stream.on('end', next);
return;
}
const chunks: Buffer[] = [];
let size = 0;
let tooLarge = false;
stream.on('data', (chunk: Buffer) => {
size += chunk.length;
if (maxBytes !== undefined && size > maxBytes) {
tooLarge = true;
return;
}
if (!tooLarge) chunks.push(chunk);
});
stream.on('end', () => {
if (!tooLarge) found = Buffer.concat(chunks);
next();
});
} else {
extract.on('entry', (header, stream, next) => {
const entryPath = normalizePath(header.name);
if (header.type === 'file' && entryPath === normalized && !found) {
if (maxBytes !== undefined && (header.size ?? 0) > maxBytes) {
stream.resume();
stream.on('end', next);
return;
}
const chunks: Buffer[] = [];
let size = 0;
let tooLarge = false;
stream.on('data', (data) => {
const chunk = data as Buffer;
size += chunk.length;
if (maxBytes !== undefined && size > maxBytes) {
tooLarge = true;
return;
}
if (!tooLarge) chunks.push(chunk);
});
stream.on('end', () => {
if (!tooLarge) found = Buffer.concat(chunks);
next();
});
} else {
stream.resume();
stream.on('end', next);
}
);
});

extract.on('finish', () => resolve(found));
extract.on('error', reject);
Expand Down Expand Up @@ -714,12 +709,9 @@ function listTarGz(
const extract = tar.extract();
const gunzip = createGunzip();

extract.on(
'entry',
(header: tar.Headers, stream: NodeJS.ReadableStream, next: (err?: Error | null) => void) => {
onTarEntry(header, stream, next, prefix, state, maxBytes);
}
);
extract.on('entry', (header, stream, next) => {
onTarEntry(header, stream, next, prefix, state, maxBytes);
});

extract.on('finish', () => {
if (state.tooLarge) {
Expand Down Expand Up @@ -748,37 +740,35 @@ function extractTarGzEntry(
const extract = tar.extract();
const gunzip = createGunzip();

extract.on(
'entry',
(header: tar.Headers, stream: NodeJS.ReadableStream, next: (err?: Error | null) => void) => {
const entryPath = normalizePath(header.name);
if (header.type === 'file' && entryPath === normalized && !found) {
if (maxBytes !== undefined && (header.size ?? 0) > maxBytes) {
stream.resume();
stream.on('end', next);
return;
}
const chunks: Buffer[] = [];
let size = 0;
let tooLarge = false;
stream.on('data', (chunk: Buffer) => {
size += chunk.length;
if (maxBytes !== undefined && size > maxBytes) {
tooLarge = true;
return;
}
if (!tooLarge) chunks.push(chunk);
});
stream.on('end', () => {
if (!tooLarge) found = Buffer.concat(chunks);
next();
});
} else {
extract.on('entry', (header, stream, next) => {
const entryPath = normalizePath(header.name);
if (header.type === 'file' && entryPath === normalized && !found) {
if (maxBytes !== undefined && (header.size ?? 0) > maxBytes) {
stream.resume();
stream.on('end', next);
return;
}
const chunks: Buffer[] = [];
let size = 0;
let tooLarge = false;
stream.on('data', (data) => {
const chunk = data as Buffer;
size += chunk.length;
if (maxBytes !== undefined && size > maxBytes) {
tooLarge = true;
return;
}
if (!tooLarge) chunks.push(chunk);
});
stream.on('end', () => {
if (!tooLarge) found = Buffer.concat(chunks);
next();
});
} else {
stream.resume();
stream.on('end', next);
}
);
});

extract.on('finish', () => resolve(found));
extract.on('error', reject);
Expand Down
Loading