From 58182bd7ed3683c512f909f1d7a1709f76ac21e9 Mon Sep 17 00:00:00 2001 From: Steven Vandevelde Date: Sat, 21 Jun 2025 14:55:04 +0200 Subject: [PATCH] refactor: only setup output configurator ui when needed --- astro.config.js | 9 +- deno.lock | 1 + package-lock.json | 7 + package.json | 1 + src/pages/configurator/output/_applet.astro | 307 +----------------- .../blur/artwork-controller/_applet.astro | 13 +- src/pages/engine/audio/_applet.astro | 3 +- src/pages/input/opensubsonic/_applet.astro | 18 +- src/pages/input/opensubsonic/types.d.ts | 9 +- src/pages/output/indexed-db/_applet.astro | 3 +- src/pages/output/native-fs/_applet.astro | 3 +- .../output/storacha-automerge/_applet.astro | 3 +- src/scripts/applet/common.ts | 48 +-- src/scripts/common.ts | 57 ++++ .../configurator/output/connections.ts | 25 ++ src/scripts/configurator/output/constants.ts | 11 + src/scripts/configurator/output/context.ts | 4 + src/scripts/configurator/output/events.ts | 6 + src/scripts/configurator/output/signals.ts | 9 + src/scripts/configurator/output/types.d.ts | 5 + src/scripts/configurator/output/ui.ts | 252 ++++++++++++++ .../input/opensubsonic/common.ts | 0 .../input/opensubsonic/constants.ts | 2 +- src/scripts/input/opensubsonic/types.d.ts | 8 + .../input/opensubsonic/ui.ts | 0 .../input/opensubsonic/worker.ts | 21 +- src/scripts/theme/blur/index.ts | 2 - tsconfig.json | 3 +- 28 files changed, 443 insertions(+), 387 deletions(-) create mode 100644 src/scripts/configurator/output/connections.ts create mode 100644 src/scripts/configurator/output/constants.ts create mode 100644 src/scripts/configurator/output/context.ts create mode 100644 src/scripts/configurator/output/events.ts create mode 100644 src/scripts/configurator/output/signals.ts create mode 100644 src/scripts/configurator/output/types.d.ts create mode 100644 src/scripts/configurator/output/ui.ts rename src/{pages => scripts}/input/opensubsonic/common.ts (100%) rename src/{pages => scripts}/input/opensubsonic/constants.ts (69%) create mode 100644 src/scripts/input/opensubsonic/types.d.ts rename src/{pages => scripts}/input/opensubsonic/ui.ts (100%) rename src/{pages => scripts}/input/opensubsonic/worker.ts (94%) diff --git a/astro.config.js b/astro.config.js index 6b4428d..b853566 100644 --- a/astro.config.js +++ b/astro.config.js @@ -1,11 +1,12 @@ import { defineConfig } from "astro/config"; import scope from "astro-scope"; import wasm from "vite-plugin-wasm"; +import worker from "@astropub/worker"; import purgecss from "astro-purgecss"; export default defineConfig({ - integrations: [scope(), purgecss()], + integrations: [scope(), purgecss(), worker()], build: { inlineStylesheets: "never", }, @@ -14,5 +15,11 @@ export default defineConfig({ server: { hmr: false, }, + build: { + target: "esnext", + }, + worker: { + format: "es", + }, }, }); diff --git a/deno.lock b/deno.lock index e619c9b..a3d3367 100644 --- a/deno.lock +++ b/deno.lock @@ -22,6 +22,7 @@ "packageJson": { "dependencies": [ "npm:98.css@~0.1.21", + "npm:@astropub/worker@0.2", "npm:@automerge/automerge@^3.0.0-beta.0", "npm:@js-temporal/polyfill@~0.5.1", "npm:@jsr/bradenmacdonald__s3-lite-client@0.9", diff --git a/package-lock.json b/package-lock.json index f824f47..ded614c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "packages": { "": { "dependencies": { + "@astropub/worker": "^0.2.0", "@automerge/automerge": "^3.0.0-beta.0", "@bradenmacdonald/s3-lite-client": "npm:@jsr/bradenmacdonald__s3-lite-client@^0.9.0", "@js-temporal/polyfill": "^0.5.1", @@ -126,6 +127,12 @@ "node": "18.20.8 || ^20.3.0 || >=22.0.0" } }, + "node_modules/@astropub/worker": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@astropub/worker/-/worker-0.2.0.tgz", + "integrity": "sha512-DkvD+H3N3n9XqRV66Jh3nYq0fPkfPwlbuOcKmLgSINms0z5VcHALVUmneceMJ1ni/MexkqffezWtGgKAiglYbw==", + "license": "(MIT-0 AND Apache-2.0)" + }, "node_modules/@automerge/automerge": { "version": "3.0.0-preview.13", "resolved": "https://registry.npmjs.org/@automerge/automerge/-/automerge-3.0.0-preview.13.tgz", diff --git a/package.json b/package.json index 83cb81b..dcb5f0c 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "dependencies": { + "@astropub/worker": "^0.2.0", "@automerge/automerge": "^3.0.0-beta.0", "@bradenmacdonald/s3-lite-client": "npm:@jsr/bradenmacdonald__s3-lite-client@^0.9.0", "@js-temporal/polyfill": "^0.5.1", diff --git a/src/pages/configurator/output/_applet.astro b/src/pages/configurator/output/_applet.astro index 0dbfde6..5e1117e 100644 --- a/src/pages/configurator/output/_applet.astro +++ b/src/pages/configurator/output/_applet.astro @@ -41,127 +41,34 @@ diff --git a/src/pages/constituent/blur/artwork-controller/_applet.astro b/src/pages/constituent/blur/artwork-controller/_applet.astro index b24fb82..2b15691 100644 --- a/src/pages/constituent/blur/artwork-controller/_applet.astro +++ b/src/pages/constituent/blur/artwork-controller/_applet.astro @@ -299,6 +299,7 @@ import "@styles/diffuse/fonts.css"; diff --git a/src/pages/input/opensubsonic/types.d.ts b/src/pages/input/opensubsonic/types.d.ts index 457b263..997decc 100644 --- a/src/pages/input/opensubsonic/types.d.ts +++ b/src/pages/input/opensubsonic/types.d.ts @@ -1,8 +1 @@ -// https://opensubsonic.netlify.app/docs/api-reference/ -export type Server = { - apiKey?: string; - host: string; - password?: string; - tls: boolean; - username?: string; -}; +export * from "@scripts/input/opensubsonic/types.d.ts"; diff --git a/src/pages/output/indexed-db/_applet.astro b/src/pages/output/indexed-db/_applet.astro index be09bcb..98a1c72 100644 --- a/src/pages/output/indexed-db/_applet.astro +++ b/src/pages/output/indexed-db/_applet.astro @@ -2,8 +2,9 @@ import * as IDB from "idb-keyval"; import type { ManagedOutput, Track } from "@applets/core/types.d.ts"; - import { jsonDecode, jsonEncode, register } from "@scripts/applet/common"; + import { register } from "@scripts/applet/common"; import { INITIAL_MANAGED_OUTPUT, outputManager } from "@scripts/output/common"; + import { jsonDecode, jsonEncode } from "@scripts/common"; //////////////////////////////////////////// // SETUP diff --git a/src/pages/output/native-fs/_applet.astro b/src/pages/output/native-fs/_applet.astro index a219c58..8cf3ecb 100644 --- a/src/pages/output/native-fs/_applet.astro +++ b/src/pages/output/native-fs/_applet.astro @@ -3,8 +3,9 @@ import type * as FSA from "wicg-file-system-access"; import type { ManagedOutput, Track } from "@applets/core/types"; - import { jsonDecode, jsonEncode, register } from "@scripts/applet/common"; + import { register } from "@scripts/applet/common"; import { INITIAL_MANAGED_OUTPUT, outputManager } from "@scripts/output/common"; + import { jsonDecode, jsonEncode } from "@scripts/common"; //////////////////////////////////////////// // SETUP diff --git a/src/pages/output/storacha-automerge/_applet.astro b/src/pages/output/storacha-automerge/_applet.astro index 8523c93..63bd7d7 100644 --- a/src/pages/output/storacha-automerge/_applet.astro +++ b/src/pages/output/storacha-automerge/_applet.astro @@ -4,8 +4,9 @@ import * as Uint8 from "uint8arrays"; import type { ManagedOutput, Track } from "@applets/core/types.d.ts"; - import { cleanUndefinedValuesForTracks, register } from "@scripts/applet/common"; + import { register } from "@scripts/applet/common"; import { INITIAL_MANAGED_OUTPUT } from "@scripts/output/common"; + import { cleanUndefinedValuesForTracks } from "@scripts/common"; //////////////////////////////////////////// // 🏔️ diff --git a/src/scripts/applet/common.ts b/src/scripts/applet/common.ts index e8067ac..2955104 100644 --- a/src/scripts/applet/common.ts +++ b/src/scripts/applet/common.ts @@ -1,13 +1,11 @@ import type { Applet, AppletEvent, AppletScope } from "@web-applets/sdk"; -import * as Uint8 from "uint8arrays"; import { applets } from "@web-applets/sdk"; import { type ElementConfigurator, h } from "spellcaster/hyperscript.js"; import { effect, isSignal, type Signal, signal } from "spellcaster/spellcaster.js"; -import { xxh32 } from "xxh32"; import QS from "query-string"; -import type { ResolvedUri, Track } from "@applets/core/types"; +import type { ResolvedUri } from "@applets/core/types"; //////////////////////////////////////////// // 🪟 Applet connecting @@ -363,32 +361,6 @@ export function appletScopePort() { return () => port; } -export function cleanUndefinedValuesForTracks(tracks: Track[]): Track[] { - return tracks.map((track) => { - const t = { ...track }; - - if (t.tags) { - if ("album" in t.tags && t.tags.album === undefined) delete t.tags.album; - if ("artist" in t.tags && t.tags.artist === undefined) delete t.tags.artist; - if ("genre" in t.tags && t.tags.genre === undefined) delete t.tags.genre; - if ("year" in t.tags && t.tags.year === undefined) delete t.tags.year; - - if ("of" in t.tags.disc && t.tags.disc.of === undefined) delete t.tags.disc.of; - if ("of" in t.tags.track && t.tags.track.of === undefined) delete t.tags.track.of; - } - - return t; - }); -} - -export function comparable(value: unknown) { - return xxh32(JSON.stringify(value)); -} - -export function inIframe() { - return window.self !== window.top; -} - export function hs( tag: string, astroScope: string, @@ -403,24 +375,6 @@ export function hs( return h(tag, propsWithScope, configure); } -export function isPrimitive(test: unknown) { - return test !== Object(test); -} - -export function jsonDecode(a: any): T { - return JSON.parse(new TextDecoder().decode(a)); -} - -export function jsonEncode(a: T): Uint8Array { - return new TextEncoder().encode(JSON.stringify(a)); -} - -export async function trackArtworkCacheId(track: Track): Promise { - return await crypto.subtle - .digest("SHA-256", new TextEncoder().encode(track.uri)) - .then((a) => Uint8.toString(new Uint8Array(a), "base64url")); -} - export function wait(applet: Applet, dataFn: (a: A | undefined) => boolean): Promise { return new Promise((resolve) => { if (dataFn(applet.data) === true) { diff --git a/src/scripts/common.ts b/src/scripts/common.ts index 7c0af9e..45731cc 100644 --- a/src/scripts/common.ts +++ b/src/scripts/common.ts @@ -1,3 +1,9 @@ +import * as Uint8 from "uint8arrays"; +import { createEndpoint, type MessageEndpoint } from "@remote-ui/rpc"; +import { xxh32 } from "xxh32"; + +import type { Track } from "@applets/core/types"; + export function arrayShuffle(array: Array): Array { if (array.length === 0) { return []; @@ -14,3 +20,54 @@ export function arrayShuffle(array: Array): Array { return array; } + +export function cleanUndefinedValuesForTracks(tracks: Track[]): Track[] { + return tracks.map((track) => { + const t = { ...track }; + + if (t.tags) { + if ("album" in t.tags && t.tags.album === undefined) delete t.tags.album; + if ("artist" in t.tags && t.tags.artist === undefined) delete t.tags.artist; + if ("genre" in t.tags && t.tags.genre === undefined) delete t.tags.genre; + if ("year" in t.tags && t.tags.year === undefined) delete t.tags.year; + + if ("of" in t.tags.disc && t.tags.disc.of === undefined) delete t.tags.disc.of; + if ("of" in t.tags.track && t.tags.track.of === undefined) delete t.tags.track.of; + } + + return t; + }); +} + +export function comparable(value: unknown) { + return xxh32(JSON.stringify(value)); +} + +export const endpoint = createEndpoint; + +export function expose>(actions: T): T { + createEndpoint(self as MessageEndpoint).expose(actions); + return actions; +} + +export function inIframe() { + return window.self !== window.top; +} + +export function isPrimitive(test: unknown) { + return test !== Object(test); +} + +export function jsonDecode(a: any): T { + return JSON.parse(new TextDecoder().decode(a)); +} + +export function jsonEncode(a: T): Uint8Array { + return new TextEncoder().encode(JSON.stringify(a)); +} + +export async function trackArtworkCacheId(track: Track): Promise { + return await crypto.subtle + .digest("SHA-256", new TextEncoder().encode(track.uri)) + .then((a) => Uint8.toString(new Uint8Array(a), "base64url")); +} diff --git a/src/scripts/configurator/output/connections.ts b/src/scripts/configurator/output/connections.ts new file mode 100644 index 0000000..1188bb1 --- /dev/null +++ b/src/scripts/configurator/output/connections.ts @@ -0,0 +1,25 @@ +import type { Applet } from "@web-applets/sdk"; + +import type { ManagedOutput } from "@applets/core/types"; +import type { Method } from "./types"; +import { CONNECTIONS, CUSTOM_KEY } from "./constants"; +import { applet } from "@scripts/applet/common"; + +const connections: Record> = {}; + +export async function connection(method: Method) { + if (connections[method]) return connections[method]; + + let href; + + if (method === "custom") { + href = localStorage.getItem(CUSTOM_KEY); + if (!href) throw new Error("Missing custom applet URL"); + } else { + href = CONNECTIONS[method]; + if (!href) throw new Error("No href defined for this connection method."); + } + + connections[method] = await applet(href); + return connections[method]; +} diff --git a/src/scripts/configurator/output/constants.ts b/src/scripts/configurator/output/constants.ts new file mode 100644 index 0000000..f6f4188 --- /dev/null +++ b/src/scripts/configurator/output/constants.ts @@ -0,0 +1,11 @@ +export const METHODS = ["browser", "custom", "device"] as const; + +export const CONNECTIONS = { + browser: "../../output/indexed-db/", + custom: undefined, + device: "../../output/native-fs/", +}; + +export const DEFAULT_METHOD: (typeof METHODS)[number] = "browser"; +export const LOCALSTORAGE_KEY = "applets/configurator/output/active-output"; +export const CUSTOM_KEY = "applets/configurator/output/custom-applet"; diff --git a/src/scripts/configurator/output/context.ts b/src/scripts/configurator/output/context.ts new file mode 100644 index 0000000..af05627 --- /dev/null +++ b/src/scripts/configurator/output/context.ts @@ -0,0 +1,4 @@ +import type { ManagedOutput } from "@applets/core/types"; +import { register } from "@scripts/applet/common"; + +export const context = register(); diff --git a/src/scripts/configurator/output/events.ts b/src/scripts/configurator/output/events.ts new file mode 100644 index 0000000..6a0b86d --- /dev/null +++ b/src/scripts/configurator/output/events.ts @@ -0,0 +1,6 @@ +import type { AppletEvent } from "@web-applets/sdk"; +import { context } from "./context"; + +export function setContextData(event: AppletEvent) { + context.data = event.data; +} diff --git a/src/scripts/configurator/output/signals.ts b/src/scripts/configurator/output/signals.ts new file mode 100644 index 0000000..a4d343a --- /dev/null +++ b/src/scripts/configurator/output/signals.ts @@ -0,0 +1,9 @@ +import { signal } from "spellcaster"; + +import type { Method } from "./types"; +import { DEFAULT_METHOD, LOCALSTORAGE_KEY, METHODS } from "./constants"; + +export const stored = localStorage.getItem(LOCALSTORAGE_KEY); +export const [active, setActive] = signal( + stored && METHODS.includes(stored as Method) ? (stored as Method) : DEFAULT_METHOD, +); diff --git a/src/scripts/configurator/output/types.d.ts b/src/scripts/configurator/output/types.d.ts new file mode 100644 index 0000000..f89ab0e --- /dev/null +++ b/src/scripts/configurator/output/types.d.ts @@ -0,0 +1,5 @@ +import { METHODS } from "./constants"; + +export type Method = (typeof METHODS)[number]; +export type List = Map>; +export type ListItem = { activated: boolean; icon: string; method: M; title: string }; diff --git a/src/scripts/configurator/output/ui.ts b/src/scripts/configurator/output/ui.ts new file mode 100644 index 0000000..d929e88 --- /dev/null +++ b/src/scripts/configurator/output/ui.ts @@ -0,0 +1,252 @@ +import { type Signal, computed, effect, signal } from "spellcaster/spellcaster.js"; +import { type ElementConfigurator, h, repeat, text } from "spellcaster/hyperscript.js"; + +import { applet, hs, reactive } from "@scripts/applet/common"; +import { CUSTOM_KEY } from "./constants"; +import { active, setActive } from "./signals"; +import { connection } from "./connections"; +import { context } from "./context"; +import type { List, ListItem, Method } from "./types"; +import { setContextData } from "./events"; + +// const h = ( +// tag: string, +// props?: Record | Signal>, +// configure?: ElementConfigurator, +// ) => hs(tag, scope, props, configure); + +//////////////////////////////////////////// +// EFFECTS +//////////////////////////////////////////// +reactive( + context.scope, + (data) => data.tracks.cacheId, + () => { + // Export data URI + const dl = document.querySelector("#download"); + if (dl) { + const json = JSON.stringify(context.data.tracks.collection, null, 2); + const href = URL.createObjectURL(new Blob([json], { type: "application/json" })); + dl.setAttribute("href", href); + } + }, +); + +// Mount + Unmount +async function mountStorageMethod(method: Method) { + switch (method) { + case "custom": + setModalIsOpen(true); + break; + default: + const conn = await connection(method); + try { + await conn.sendAction("mount", undefined, { timeoutDuration: 60000 }); + setActive(method); + } catch (err) { + const msg: string = + err && typeof err === "object" && "message" in err ? `${err.message}` : `${err}`; + if (msg.startsWith("[user] ")) alert(msg.slice(7)); + } + break; + } +} + +async function unmountStorageMethod(method: Method) { + const conn = await connection(method); + conn.removeEventListener("data", setContextData); + await conn.sendAction("unmount", undefined, { timeoutDuration: 60000 }); +} + +//////////////////////////////////////////// +// LIST +//////////////////////////////////////////// +const list = computed(() => { + const a = active(); + + return new Map([ + [ + `browser-${a === "browser"}`, + { + title: "Browser storage", + icon: "iconoir-app-window", + method: "browser", + activated: a === "browser", + }, + ], + [ + `device-${a === "device"}`, + { + title: "Device storage", + icon: "iconoir-laptop", + method: "device", + activated: a === "device", + }, + ], + [ + `custom-${a === "custom"}`, + { + title: "Custom applet", + icon: "iconoir-globe", + method: "custom", + activated: a === "custom", + }, + ], + ]); +}); + +const Item = (signal: Signal>) => { + const item = signal(); + + const colorClass = item.activated ? "pico-color-jade-500" : "pico-color-grey-500"; + const icon = item.activated ? "iconoir-check-circle-solid" : "iconoir-check-circle"; + + return h( + "p", + { + onclick: clickHandler(item.method), + style: "cursor: pointer", + }, + [ + h("span", { className: "with-icon" }, [ + h("i", { className: item.icon }), + h("strong", {}, text(item.title)), + ]), + h("br"), + h("span", { className: `with-icon ${colorClass}` }, [ + h("i", { className: icon }), + h("span", {}, text(item.activated ? "Active" : "Select")), + ]), + ], + ); +}; + +function clickHandler(method: Method) { + return async () => { + const currentlyActive = active(); + if (currentlyActive === method && currentlyActive !== "custom") return; + if (currentlyActive) unmountStorageMethod(currentlyActive); + await mountStorageMethod(method); + }; +} + +const Options = computed(() => { + return h("div", { id: "options" }, repeat(list, Item)); +}); + +// Add to DOM +document.getElementById("options")?.replaceWith(Options()); + +//////////////////////////////////////////// +// CUSTOM APPLET +//////////////////////////////////////////// +type CustomAppletState = "waiting" | "connecting" | { error: string } | "connected"; + +const [modalIsOpen, setModalIsOpen] = signal(false); +const [customState, setCustomState] = signal("waiting"); + +const Modal = () => { + const Header = h("header", {}, [ + h("button", { + attrs: { rel: "prev" }, + ariaLabel: "Close", + onclick: close, + }), + h("p", {}, [ + h("strong", {}, [ + h("span", { className: "with-icon" }, [ + h("i", { className: "iconoir-globe" }), + h("span", {}, text("Load a custom applet")), + ]), + ]), + ]), + ]); + + const Content = h("form", { onsubmit: submit }, [ + h("fieldset", { role: "group" }, [ + h("input", { + type: "url", + name: "url", + placeholder: "https://applets.diffuse.sh/storage/output/indexed-db/", + required: true, + value: localStorage.getItem(CUSTOM_KEY) || "", + }), + h("input", { type: "submit", value: "Connect" }), + ]), + h("p", {}, [ + h("small", { className: "with-icon" }, (element) => { + const comp = computed(() => { + const s = customState(); + + if (s === "connecting") { + return [ + h("i", { className: "iconoir-ev-plug-charging" }), + h("span", {}, text("Connecting ...")), + ]; + } else if (typeof s !== "string") { + return [ + h("i", { className: "iconoir-warning-circle" }), + h("span", {}, text(`Error: ${s.error}`)), + ]; + } + + return [h("span", {}, text("Enter the URL to the applet."))]; + }); + + effect(() => { + element.replaceChildren(...comp()); + }); + }), + ]), + ]); + + return h( + "dialog", + computed(() => ({ open: modalIsOpen() })), + [h("article", {}, [Header, Content])], + ); +}; + +// Events +function close() { + setModalIsOpen(false); +} + +async function submit(event: SubmitEvent) { + event.preventDefault(); + + const input: HTMLInputElement | null = (event.target as HTMLFormElement).querySelector( + `input[type="url"]`, + ); + + if (!input) return; + + const url = input.value; + setCustomState("connecting"); + + const apl = await applet(url).catch((err) => { + setCustomState({ error: "Failed to connect" }); + throw err; + }); + + let missingAction; + + ["tracks", "mount", "unmount"].forEach((method) => { + if (!apl.manifest.actions?.[method]) missingAction = method; + }); + + if (missingAction) { + setCustomState({ error: `Applet is missing a required action: "${missingAction}"` }); + return; + } + + localStorage.setItem(CUSTOM_KEY, url); + await apl.sendAction("mount", undefined, { timeoutDuration: 60000 }); + + setActive("custom"); + setModalIsOpen(false); + setCustomState("waiting"); +} + +// Add to DOM +document.querySelector("main")?.appendChild(Modal()); diff --git a/src/pages/input/opensubsonic/common.ts b/src/scripts/input/opensubsonic/common.ts similarity index 100% rename from src/pages/input/opensubsonic/common.ts rename to src/scripts/input/opensubsonic/common.ts diff --git a/src/pages/input/opensubsonic/constants.ts b/src/scripts/input/opensubsonic/constants.ts similarity index 69% rename from src/pages/input/opensubsonic/constants.ts rename to src/scripts/input/opensubsonic/constants.ts index e1232f5..91c678b 100644 --- a/src/pages/input/opensubsonic/constants.ts +++ b/src/scripts/input/opensubsonic/constants.ts @@ -1,4 +1,4 @@ -import manifest from "./_manifest.json"; +import manifest from "../../../pages/input/opensubsonic/_manifest.json"; export const IDB_PREFIX = "@applets/input/opensubsonic"; export const IDB_SERVERS = `${IDB_PREFIX}/servers`; diff --git a/src/scripts/input/opensubsonic/types.d.ts b/src/scripts/input/opensubsonic/types.d.ts new file mode 100644 index 0000000..457b263 --- /dev/null +++ b/src/scripts/input/opensubsonic/types.d.ts @@ -0,0 +1,8 @@ +// https://opensubsonic.netlify.app/docs/api-reference/ +export type Server = { + apiKey?: string; + host: string; + password?: string; + tls: boolean; + username?: string; +}; diff --git a/src/pages/input/opensubsonic/ui.ts b/src/scripts/input/opensubsonic/ui.ts similarity index 100% rename from src/pages/input/opensubsonic/ui.ts rename to src/scripts/input/opensubsonic/ui.ts diff --git a/src/pages/input/opensubsonic/worker.ts b/src/scripts/input/opensubsonic/worker.ts similarity index 94% rename from src/pages/input/opensubsonic/worker.ts rename to src/scripts/input/opensubsonic/worker.ts index 31f8ae6..a914dd8 100644 --- a/src/pages/input/opensubsonic/worker.ts +++ b/src/scripts/input/opensubsonic/worker.ts @@ -1,4 +1,3 @@ -import { createEndpoint, type MessageEndpoint } from "@remote-ui/rpc"; import { SubsonicAPI, type Child } from "subsonic-api"; import * as URI from "uri-js"; import QS from "query-string"; @@ -7,19 +6,21 @@ import type { Track } from "@applets/core/types.d.ts"; import type { Server } from "./types.d.ts"; import { SCHEME } from "./constants.ts"; import { loadServers, serverId } from "./common.ts"; +import { expose } from "../../../scripts/common.ts"; //////////////////////////////////////////// // ACTIONS //////////////////////////////////////////// -const actions = createEndpoint(self as MessageEndpoint); -actions.expose({ consult, contextualize, list, resolve }); - -export type Actions = { - consult: typeof consult; - contextualize: typeof contextualize; - list: typeof list; - resolve: typeof resolve; -}; +const actions = expose({ + consult, + contextualize, + list, + resolve, +}); + +export type Actions = typeof actions; + +// Actions async function consult(fileUriOrScheme: string) { // TODO: Check if server is available + CORS works? diff --git a/src/scripts/theme/blur/index.ts b/src/scripts/theme/blur/index.ts index f51574d..d28167f 100644 --- a/src/scripts/theme/blur/index.ts +++ b/src/scripts/theme/blur/index.ts @@ -1,5 +1,3 @@ -import type { Applet } from "@web-applets/sdk"; - import type { ManagedOutput } from "@applets/core/types"; import { applet, reactive, wait } from "@scripts/applet/common"; diff --git a/tsconfig.json b/tsconfig.json index f45eb8b..8b93767 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,9 +8,10 @@ "esModuleInterop": true, "experimentalDecorators": false, "isolatedModules": true, + "lib": ["DOM", "ESNext", "WebWorker"], "module": "esnext", "moduleResolution": "bundler", - "moduleDetection": "force", + "moduleDetection": "auto", "noEmit": true, "noImplicitOverride": true, "skipLibCheck": true, -- knotmirror 0.0.1