diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml index beeb8991..c0ee889a 100644 --- a/.github/workflows/web.yml +++ b/.github/workflows/web.yml @@ -40,13 +40,13 @@ jobs: # - name: Lint # run: deno task lint - # - name: Typecheck - # run: deno task check - # package.json based projects need to run deno install step - name: Install Dependencies run: deno install --allow-scripts + - name: Typecheck + run: deno task check + - name: Build run: deno task build diff --git a/deno.lock b/deno.lock index e55205d4..c3467fd0 100644 --- a/deno.lock +++ b/deno.lock @@ -67,6 +67,13 @@ "jsr:@torm/sqlite@^1.9.7": "1.9.7", "npm:@deno/vite-plugin@1.0.6": "1.0.6_vite@7.1.8__@types+node@24.2.0__picomatch@4.0.3_@types+node@24.2.0", "npm:@jsr/andykais__ts-rpc@~0.2.4": "0.2.4_@sveltejs+vite-plugin-svelte@6.2.1__svelte@5.39.8___acorn@8.15.0__vite@7.1.8___@types+node@24.2.0___picomatch@4.0.3__@types+node@24.2.0_svelte@5.39.8__acorn@8.15.0_vite@7.1.8__@types+node@24.2.0__picomatch@4.0.3_@types+node@24.2.0", + "npm:@jsr/std__datetime@~0.225.3": "0.225.7", + "npm:@jsr/std__fmt@0.225.6": "0.225.6", + "npm:@jsr/std__fs@0.229.3": "0.229.3", + "npm:@jsr/std__log@~0.224.6": "0.224.14", + "npm:@jsr/std__media-types@0.224.0": "0.224.0", + "npm:@jsr/std__path@1.0.3": "1.0.3", + "npm:@jsr/std__yaml@^1.0.5": "1.1.2", "npm:@jsr/torm__sqlite@^1.9.7": "1.9.7", "npm:@opentelemetry/api@1.9.0": "1.9.0", "npm:@opentelemetry/api@^1.9.0": "1.9.0", @@ -74,11 +81,13 @@ "npm:@sveltejs/kit@2.5.24": "2.5.24_@sveltejs+vite-plugin-svelte@6.2.1__svelte@5.39.8___acorn@8.15.0__vite@7.1.8___@types+node@24.2.0___picomatch@4.0.3__@types+node@24.2.0_svelte@5.39.8__acorn@8.15.0_vite@7.1.8__@types+node@24.2.0__picomatch@4.0.3_@types+node@24.2.0", "npm:@sveltejs/vite-plugin-svelte@6.2.1": "6.2.1_svelte@5.39.8__acorn@8.15.0_vite@7.1.8__@types+node@24.2.0__picomatch@4.0.3_@types+node@24.2.0", "npm:@tailwindcss/vite@4.1.14": "4.1.14_vite@7.1.8__@types+node@24.2.0__picomatch@4.0.3_@types+node@24.2.0", + "npm:@types/deno@^2.5.0": "2.7.0", "npm:@types/node@*": "24.2.0", "npm:esbuild@*": "0.25.10", "npm:path-to-regexp@6.2.1": "6.2.1", "npm:sv@*": "0.12.5", "npm:sv@latest": "0.12.5", + "npm:svelte-check@*": "4.3.2_svelte@5.39.8__acorn@8.15.0_typescript@5.9.3", "npm:svelte-check@4.3.2": "4.3.2_svelte@5.39.8__acorn@8.15.0_typescript@5.9.3", "npm:svelte@5.39.8": "5.39.8_acorn@8.15.0", "npm:svelte@~5.39.8": "5.39.8_acorn@8.15.0", @@ -574,7 +583,7 @@ "@jsr/std__assert@0.226.0": { "integrity": "sha512-xCuUFDfHkIZd96glKgjZbnYFqu6blu8Y53SyvDMlFDJm1Y/j+/FcW6xq7TzGFIaF5B9QecIlDfamfhzA8ZdVbg==", "dependencies": [ - "@jsr/std__internal@1.0.10" + "@jsr/std__internal@1.0.14" ], "tarball": "https://npm.jsr.io/~/11/@jsr/std__assert/0.226.0.tgz" }, @@ -628,6 +637,10 @@ ], "tarball": "https://npm.jsr.io/~/11/@jsr/std__crypto/0.224.0.tgz" }, + "@jsr/std__datetime@0.225.7": { + "integrity": "sha512-z1N0Ompk9zzcrwExq2uMxGAvnXDjV9W9m5Lun+OE27/Y2F+jvDWdZ766a28h+U3XKKoDq0hByYVuhOZ7pzWuhw==", + "tarball": "https://npm.jsr.io/~/11/@jsr/std__datetime/0.225.7.tgz" + }, "@jsr/std__encoding@0.223.0": { "integrity": "sha512-auQ0wUZFsVGXU+6qfjGeonWe8utBhp+y43etR1lanCJXXUzL5W3yS+i73Fki+RLjvxUG4Pwd1CrGSR57kIvrIg==", "tarball": "https://npm.jsr.io/~/11/@jsr/std__encoding/0.223.0.tgz" @@ -652,6 +665,25 @@ "integrity": "sha512-5wll7CImyrJfen4fecziNSxZ5S6Fo3H1rQqKMQDewRGHAnFVqcHLe8wwCuDLK+HTbSPy6AkR3b136WpjVdOjTQ==", "tarball": "https://npm.jsr.io/~/11/@jsr/std__fmt/0.225.6.tgz" }, + "@jsr/std__fmt@1.0.10": { + "integrity": "sha512-Q2N8XDNkh/c1IKTi+sO4Vm64M5m4W0o47qTURmMX0vgHm9AJ6jL7jEQ2kw0M1T2rBZiwAY78eUbYzFyOYWaCqQ==", + "tarball": "https://npm.jsr.io/~/11/@jsr/std__fmt/1.0.10.tgz" + }, + "@jsr/std__fs@0.229.3": { + "integrity": "sha512-hXsLcP1dumz3VbRKVhPtzs7Wigxhqp2rtBzwzrF9Cz9IMqZkp7EoKHxeqcUiduf7yYxVV/vbnfhjqbOLvlljjA==", + "dependencies": [ + "@jsr/std__path@1.0.0-rc.1" + ], + "tarball": "https://npm.jsr.io/~/11/@jsr/std__fs/0.229.3.tgz" + }, + "@jsr/std__fs@1.0.24": { + "integrity": "sha512-UunW2Rg++9sA74NJnYMGTsMVQgoFRAwPP02wRRohL0PQBNorbyxHiyCMRaxYQCtLepTLkC4nUyMtcwrGKqTR6g==", + "dependencies": [ + "@jsr/std__internal@1.0.14", + "@jsr/std__path@1.1.6" + ], + "tarball": "https://npm.jsr.io/~/11/@jsr/std__fs/1.0.24.tgz" + }, "@jsr/std__http@0.223.0": { "integrity": "sha512-v60Hv8J1GXM1ExsJgBXVcmhbyt4Ip3RFaIdkVrycujbBL5qFuhNnvkmggAonP+nwXy5V0crU/tkLNWTyncoPXQ==", "dependencies": [ @@ -687,9 +719,9 @@ ], "tarball": "https://npm.jsr.io/~/11/@jsr/std__internal/0.224.0.tgz" }, - "@jsr/std__internal@1.0.10": { - "integrity": "sha512-fmD6yKep/sMnB2yPQU/REZG7Z4N9SZwcUBNnceo4QkXk67l3JEfxHoROQ/YHeVSOmq6x55Ra6nuMjz2ib3nj3g==", - "tarball": "https://npm.jsr.io/~/11/@jsr/std__internal/1.0.10.tgz" + "@jsr/std__internal@1.0.14": { + "integrity": "sha512-JT8b/t40WcR9q0GDwRZUooY7aXeXnFal8iidE/5TckdAFtvpVAsaJ71/Xgf1SfoChs41s6CZkuCYM8toaNgdvA==", + "tarball": "https://npm.jsr.io/~/11/@jsr/std__internal/1.0.14.tgz" }, "@jsr/std__io@0.223.0": { "integrity": "sha512-VUPpfHeLvhooQFyujLSj6/KDCqgF+joBpb6eO9dg+JJWvy5wHj1Nl2EMRQe6Pl8nNVUwjt+ZraydkGTdlDS1jw==", @@ -706,10 +738,30 @@ ], "tarball": "https://npm.jsr.io/~/11/@jsr/std__io/0.224.9.tgz" }, + "@jsr/std__io@0.225.3": { + "integrity": "sha512-IDXY253ipW6FV34CJVxO+3ubfvSEEzw9N2W303KnLe9K/Y9+v/ID1dQYf9VsCCOFMpFtCmOLqzIZsRqv6yQnWw==", + "dependencies": [ + "@jsr/std__bytes@1.0.6" + ], + "tarball": "https://npm.jsr.io/~/11/@jsr/std__io/0.225.3.tgz" + }, + "@jsr/std__log@0.224.14": { + "integrity": "sha512-EHT7E0plakyzk/gxMrwqUf3YGCCxN3Is25QrEh7toYA7qwj46R4qY7cIaDEKy8QqI5JHOFHwWXOClcPK6goIoQ==", + "dependencies": [ + "@jsr/std__fmt@1.0.10", + "@jsr/std__fs@1.0.24", + "@jsr/std__io@0.225.3" + ], + "tarball": "https://npm.jsr.io/~/11/@jsr/std__log/0.224.14.tgz" + }, "@jsr/std__media-types@0.223.0": { "integrity": "sha512-wJe0dRZiL1OqU8oGXReVuMK5stHERyGgpR/6yS4qW9+p74+XXSIP+OGubfzl8TjeKeULd82zLbk1QNo5FvwXNw==", "tarball": "https://npm.jsr.io/~/11/@jsr/std__media-types/0.223.0.tgz" }, + "@jsr/std__media-types@0.224.0": { + "integrity": "sha512-ua4EvwuGmFFB0KREfJGROd+EeVxGE6IwNJnfP4jHGyIuH7JLxX78r1cNbPxVjTrNso2GbjFdBQ2pKcyPQOOhUQ==", + "tarball": "https://npm.jsr.io/~/11/@jsr/std__media-types/0.224.0.tgz" + }, "@jsr/std__media-types@0.224.1": { "integrity": "sha512-L3kF5zNOA0KNibbdKwxmjaHUOpa7vWTb6BNwv41QZEjOtmS8GWPTRAXkglLEUfu2gl6pXlOoT3BmXv/naO5tKA==", "tarball": "https://npm.jsr.io/~/11/@jsr/std__media-types/0.224.1.tgz" @@ -729,10 +781,25 @@ ], "tarball": "https://npm.jsr.io/~/11/@jsr/std__path/0.223.0.tgz" }, + "@jsr/std__path@1.0.0-rc.1": { + "integrity": "sha512-bGolWCcaF8HGT0QVZr/heEaHm6MEgpOI7LyrV4JLuBYrLb81FAX7m3Li77JnF06RNhJViY8K7zvPpuVIiakyvA==", + "tarball": "https://npm.jsr.io/~/11/@jsr/std__path/1.0.0-rc.1.tgz" + }, "@jsr/std__path@1.0.0-rc.2": { "integrity": "sha512-qUHfVMqAtMGPFmdkOfmkCONqgpe4UFVAaD+wL6ZdlQxtvQiNxHQWsje+djri+0095s/kkoBOPH4CpYxBq+zh3A==", "tarball": "https://npm.jsr.io/~/11/@jsr/std__path/1.0.0-rc.2.tgz" }, + "@jsr/std__path@1.0.3": { + "integrity": "sha512-XH7cE38WHq4J3ICVKrVs0GvKf9EXfMxAzvXkVewHXJeyh7TW/bN47yIPArDQUybHlyLkTQvQaDW0hWDY3TP2xQ==", + "tarball": "https://npm.jsr.io/~/11/@jsr/std__path/1.0.3.tgz" + }, + "@jsr/std__path@1.1.6": { + "integrity": "sha512-H1Cmg6z8jFyIsQbVV+vZB4eOx4k6Qg8lyUM6l7nZysj5MZumg89kb0M1bsPBTGQis3fw6mJFkJELo5+AK6oCFA==", + "dependencies": [ + "@jsr/std__internal@1.0.14" + ], + "tarball": "https://npm.jsr.io/~/11/@jsr/std__path/1.1.6.tgz" + }, "@jsr/std__streams@0.223.0": { "integrity": "sha512-YfOfRTpnTocgC5h22aRMgu74ByBO6763PgwG2p7iFWYZFBRrDNW6WqYK1MFXcbU8VrwlgpUEvkS3Xk9dJnd+hw==", "dependencies": [ @@ -750,6 +817,10 @@ ], "tarball": "https://npm.jsr.io/~/11/@jsr/std__streams/0.224.5.tgz" }, + "@jsr/std__yaml@1.1.2": { + "integrity": "sha512-R2U09+AG6VgFet8qmVhkFw1eKQKeG54RAejd64G5F0XrzMFmHp6KOMnabOdSowd7kj28wFt/x4XT2ARGZEEeVw==", + "tarball": "https://npm.jsr.io/~/11/@jsr/std__yaml/1.1.2.tgz" + }, "@jsr/torm__sqlite@1.9.7": { "integrity": "sha512-naligACB12UtWD43fd0QtUCIgNotPoiib3r/qFHAMj0Hy2RxapfR24dSH2U5gHQM4DSBCt2/sqwcjojY2T3SMw==", "dependencies": [ @@ -1060,6 +1131,9 @@ "@types/cookie@0.6.0": { "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==" }, + "@types/deno@2.7.0": { + "integrity": "sha512-Y6fWcV8KpYeO3Lik/RiYnUxtr/LWqoeACciU0CA+dr1U/45tGgaX3HWQQAPCNN53raN4Rr4Fht4y6qsUH57fDA==" + }, "@types/estree@1.0.8": { "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==" }, @@ -1549,17 +1623,27 @@ "dependencies": [ "npm:@deno/vite-plugin@1.0.6", "npm:@jsr/andykais__ts-rpc@~0.2.4", + "npm:@jsr/std__datetime@~0.225.3", + "npm:@jsr/std__fmt@0.225.6", + "npm:@jsr/std__fs@0.229.3", + "npm:@jsr/std__log@~0.224.6", + "npm:@jsr/std__media-types@0.224.0", + "npm:@jsr/std__path@1.0.3", + "npm:@jsr/std__yaml@^1.0.5", "npm:@jsr/torm__sqlite@^1.9.7", "npm:@opentelemetry/api@1.9.0", "npm:@sveltejs/kit@2.43.7", "npm:@sveltejs/vite-plugin-svelte@6.2.1", "npm:@tailwindcss/vite@4.1.14", + "npm:@types/deno@^2.5.0", "npm:svelte-check@4.3.2", "npm:svelte@5.39.8", "npm:tailwindcss@4.1.14", + "npm:ts-pattern@5.2.0", "npm:typescript-svelte-plugin@0.3.50", "npm:typescript@5.9.3", - "npm:vite@7.1.8" + "npm:vite@7.1.8", + "npm:zod@4.1.11" ] } }, diff --git a/packages/core/src/lib/file_processor.ts b/packages/core/src/lib/file_processor.ts index b2212c42..26e3ca3c 100644 --- a/packages/core/src/lib/file_processor.ts +++ b/packages/core/src/lib/file_processor.ts @@ -649,7 +649,12 @@ class FileProcessor { } async * #readlines(stream: ReadableStream) { - const reader = stream.pipeThrough(new TextDecoderStream()).getReader() + // TextDecoderStream types its writable side as WritableStream, which + // TypeScript's DOM lib does not treat as assignable to the WritableStream + // that pipeThrough infers. The pairing is valid at runtime (a Uint8Array is a + // BufferSource), so bridge the lib-level mismatch explicitly. + const decoder = new TextDecoderStream() as ReadableWritablePair + const reader = stream.pipeThrough(decoder).getReader() let buffer = '' let read_result = await reader.read() while (!read_result.done) { diff --git a/packages/web/package.json b/packages/web/package.json index 35993e91..a433f4ac 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -8,19 +8,29 @@ "build": "vite build", "build:local": "LOCAL_BUILD=true vite build", "prepare": "svelte-kit sync || echo ''", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.svelte.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.svelte.json --watch" }, "dependencies": { "@andykais/ts-rpc": "npm:@jsr/andykais__ts-rpc@^0.2.4", "@opentelemetry/api": "1.9.0", - "@torm/sqlite": "npm:@jsr/torm__sqlite@^1.9.7" + "@std/datetime": "npm:@jsr/std__datetime@^0.225.3", + "@std/fmt": "npm:@jsr/std__fmt@0.225.6", + "@std/fs": "npm:@jsr/std__fs@0.229.3", + "@std/log": "npm:@jsr/std__log@^0.224.6", + "@std/media-types": "npm:@jsr/std__media-types@0.224.0", + "@std/path": "npm:@jsr/std__path@1.0.3", + "@std/yaml": "npm:@jsr/std__yaml@^1.0.5", + "@torm/sqlite": "npm:@jsr/torm__sqlite@^1.9.7", + "ts-pattern": "npm:ts-pattern@5.2.0", + "zod": "npm:zod@4.1.11" }, "devDependencies": { "@deno/vite-plugin": "1.0.6", "@sveltejs/kit": "2.43.7", "@sveltejs/vite-plugin-svelte": "6.2.1", "@tailwindcss/vite": "4.1.14", + "@types/deno": "^2.5.0", "svelte": "5.39.8", "svelte-check": "4.3.2", "tailwindcss": "4.1.14", diff --git a/packages/web/src/app.d.ts b/packages/web/src/app.d.ts index da08e6da..591e5d15 100644 --- a/packages/web/src/app.d.ts +++ b/packages/web/src/app.d.ts @@ -1,9 +1,15 @@ // See https://svelte.dev/docs/kit/types#app.d.ts // for information about these interfaces +import type { Forager } from '@forager/core' +import type { Config } from '$lib/server/config.ts' + declare global { namespace App { // interface Error {} - // interface Locals {} + interface Locals { + forager: Forager + config: Config + } // interface PageData {} // interface PageState {} // interface Platform {} diff --git a/packages/web/src/hooks.server.ts b/packages/web/src/hooks.server.ts index d6b8e76f..787bc67a 100644 --- a/packages/web/src/hooks.server.ts +++ b/packages/web/src/hooks.server.ts @@ -29,8 +29,10 @@ if (!building) { forager.init() } else { if (env.FORAGER_INSTANCE) { - forager = env.FORAGER_INSTANCE - config = env.FORAGER_CONFIG + // In production the CLI injects a live Forager instance and parsed config + // through these env slots, so they are not the plain strings $env types them as. + forager = env.FORAGER_INSTANCE as unknown as Forager + config = env.FORAGER_CONFIG as unknown as Config } else { throw new Error(`FORAGER_INSTANCE must be passed to sveltekit hooks`) } diff --git a/packages/web/src/lib/actions/focusable.ts b/packages/web/src/lib/actions/focusable.ts index c4534a0d..c04dfab6 100644 --- a/packages/web/src/lib/actions/focusable.ts +++ b/packages/web/src/lib/actions/focusable.ts @@ -1,11 +1,15 @@ -export function focusable(node: HTMLElement) { +export function focusable(node: HTMLElement, focused: boolean) { + const apply = (should_focus: boolean) => { + if (should_focus) { + node.focus() + } else { + node.blur() + } + } + apply(focused) return { - update(focused: boolean) { - if (focused) { - node.focus() - } else { - node.blur() - } + update(should_focus: boolean) { + apply(should_focus) } } diff --git a/packages/web/src/lib/actions/scrollable.ts b/packages/web/src/lib/actions/scrollable.ts index ea361469..991ec967 100644 --- a/packages/web/src/lib/actions/scrollable.ts +++ b/packages/web/src/lib/actions/scrollable.ts @@ -1,4 +1,4 @@ -export function scrollable(node: HTMLElement) { +export function scrollable(node: HTMLElement, _focused: boolean) { let is_visible = false const observer = new IntersectionObserver((entries) => { is_visible = entries[0].isIntersecting diff --git a/packages/web/src/lib/api.ts b/packages/web/src/lib/api.ts index 039ddc95..b871b0d0 100644 --- a/packages/web/src/lib/api.ts +++ b/packages/web/src/lib/api.ts @@ -18,11 +18,37 @@ class ForagerTagApi extends rpc.ApiController { parent_delete = this.context.forager.tag.parent_delete } +class ForagerMediaApi extends rpc.ApiController { + create = this.context.forager.media.create + update = this.context.forager.media.update + upsert = this.context.forager.media.upsert + delete = this.context.forager.media.delete + search = this.context.forager.media.search + group = this.context.forager.media.group + get = this.context.forager.media.get + thumbnail = this.context.forager.media.thumbnail + reload = this.context.forager.media.reload +} + +class ForagerSeriesApi extends rpc.ApiController { + create = this.context.forager.series.create + update = this.context.forager.series.update + upsert = this.context.forager.series.upsert + add = this.context.forager.series.add + get = this.context.forager.series.get + search = this.context.forager.series.search +} + +class ForagerViewsApi extends rpc.ApiController { + start = this.context.forager.views.start + update = this.context.forager.views.update +} + class ForagerApi extends rpc.ApiController { - media = this.context.forager.media - series = this.context.forager.series + media = this.module(ForagerMediaApi) + series = this.module(ForagerSeriesApi) tag = this.module(ForagerTagApi) - views = this.context.forager.views + views = this.module(ForagerViewsApi) } diff --git a/packages/web/src/lib/base_controller.ts b/packages/web/src/lib/base_controller.ts index b221163e..9d0499b2 100644 --- a/packages/web/src/lib/base_controller.ts +++ b/packages/web/src/lib/base_controller.ts @@ -26,8 +26,6 @@ abstract class BaseController { if (this.#config) return this.#config else throw new Error(`Controller::config not initialized`) } - - abstract handlers: {} } export { BaseController } diff --git a/packages/web/src/lib/components/Header.svelte b/packages/web/src/lib/components/Header.svelte index 4ed3a0e7..18387468 100644 --- a/packages/web/src/lib/components/Header.svelte +++ b/packages/web/src/lib/components/Header.svelte @@ -8,6 +8,7 @@ ...props }: { title: string + height?: number children: SvelteHTMLElements['div']['children'] } = $props() diff --git a/packages/web/src/lib/components/SelectInput.svelte b/packages/web/src/lib/components/SelectInput.svelte index f8b7e702..428ec35c 100644 --- a/packages/web/src/lib/components/SelectInput.svelte +++ b/packages/web/src/lib/components/SelectInput.svelte @@ -4,10 +4,10 @@ value: string } interface Props { - label: string - options: SelectOption + label?: string + options: SelectOption[] value: string - onchange: () => void | undefined + onchange?: (e: Event) => void } let { label, diff --git a/packages/web/src/lib/components/StarInput.svelte b/packages/web/src/lib/components/StarInput.svelte index b72f7bbf..53ae452e 100644 --- a/packages/web/src/lib/components/StarInput.svelte +++ b/packages/web/src/lib/components/StarInput.svelte @@ -5,16 +5,16 @@ let { star, - value = $bindable(), + value = $bindable(), onclick, }: { star: number - value: number + value: number | undefined onclick: () => void } = $props() let icon_color = $derived.by(() => { - if (value >= star) { + if ((value ?? 0) >= star) { // starred return theme.colors.gray[400] } else { diff --git a/packages/web/src/lib/components/Tag.svelte b/packages/web/src/lib/components/Tag.svelte index ba630442..8fe0c232 100644 --- a/packages/web/src/lib/components/Tag.svelte +++ b/packages/web/src/lib/components/Tag.svelte @@ -1,9 +1,9 @@ @@ -68,11 +68,11 @@ class="rounded-md py-1 px-3 text-slate-100 bg-gray-800 text-sm min-h-16" bind:value={controller.draft.description} > - + Media - + Unread - + Created
@@ -148,7 +148,7 @@ } }}>
- + Set this tag as an alias that hides the following tags: { get URL_PARAM_MAP() { return URL_PARAM_MAP } constructor(client: BaseController['client']) { - super(client) + super(client, DEFAULTS) } #build_search_options(params: SearchParams, limit: number) { diff --git a/packages/web/svelte.config.js b/packages/web/svelte.config.js index 02299a17..02a9423f 100644 --- a/packages/web/svelte.config.js +++ b/packages/web/svelte.config.js @@ -9,9 +9,6 @@ const config = { kit: { adapter: adapter(), - experimental: { - remoteFunctions: true, - }, prerender: { crawl: false, entries: [] diff --git a/packages/web/tsconfig.svelte.json b/packages/web/tsconfig.svelte.json new file mode 100644 index 00000000..5032adf0 --- /dev/null +++ b/packages/web/tsconfig.svelte.json @@ -0,0 +1,53 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler", + + // `@forager/core` is a Deno project whose source is pulled into the program + // by the path mapping below. `verbatimModuleSyntax` is disabled so its + // (Deno-valid) value/type imports don't surface here, and `DOM.AsyncIterable` + // is added so async-iterable web streams (e.g. `for await (…of readable)`) + // type-check the same way they run under Deno. + "verbatimModuleSyntax": false, + "lib": ["esnext", "DOM", "DOM.Iterable", "DOM.AsyncIterable"], + + "plugins": [{ + "name": "typescript-svelte-plugin", + "enabled": true, + "assumeIsSvelteProject": true + }], + + "allowImportingTsExtensions": true, + + "baseUrl": ".", + // NOTE: `paths` fully replaces the mapping inherited from + // ./.svelte-kit/tsconfig.json (TypeScript does not merge `paths` across + // `extends`), so the SvelteKit `$lib`/`$app` aliases are re-declared here + // relative to this file's location, alongside the workspace aliases. + "paths": { + "~/*": ["../core/src/*"], + "@forager/core": ["../core/src/mod.ts"], + "$lib": ["./src/lib"], + "$lib/*": ["./src/lib/*"], + "$app/types": ["./.svelte-kit/types/index.d.ts"] + } + }, + // `@forager/core` is resolved to its TypeScript source so svelte-check can infer + // types across the workspace, but the core package is excluded from the checked + // fileset since it is a Deno project that is type-checked separately. + "exclude": [ + "node_modules/**", + "../node_modules/**", + "../../node_modules/**", + "../core/**/*", + "../core/**" + ] +} diff --git a/packages/web/vite.config.ts b/packages/web/vite.config.ts index c7bd6c15..2c3ba88e 100644 --- a/packages/web/vite.config.ts +++ b/packages/web/vite.config.ts @@ -10,7 +10,7 @@ const monorepo_root = path.resolve(__dirname, '..', '..') * Note that npm depedencies like you may put into package.json like `npm:@jsr/torm__sqlite@^1.9.7` do _not_ work */ function resolve_workspace_imports(workspace_package: string) { const package_root = path.join(monorepo_root, 'packages', workspace_package) - const denojson = JSON.parse(new TextDecoder().decode(Deno.readFileSync(path.join(package_root, 'deno.json')))) + const denojson: { imports: Record } = JSON.parse(new TextDecoder().decode(Deno.readFileSync(path.join(package_root, 'deno.json')))) const resolved_imports: Record = {} for (const [package_alias, specifier] of Object.entries(denojson.imports)) {