diff --git a/src/pages/processor/artwork/_applet.astro b/src/pages/processor/artwork/_applet.astro
index 19adef7..5b7e1dc 100644
--- a/src/pages/processor/artwork/_applet.astro
+++ b/src/pages/processor/artwork/_applet.astro
@@ -1,15 +1,12 @@
diff --git a/src/scripts/applet/common.ts b/src/scripts/applet/common.ts
index d924503..3d5dd6f 100644
--- a/src/scripts/applet/common.ts
+++ b/src/scripts/applet/common.ts
@@ -1,4 +1,5 @@
import type { Applet, AppletEvent, AppletScope } from "@web-applets/sdk";
+import type * as Comlink from "comlink";
import { applets } from "@web-applets/sdk";
import { type ElementConfigurator, h } from "spellcaster/hyperscript.js";
@@ -6,6 +7,7 @@ import { effect, isSignal, type Signal, signal } from "spellcaster/spellcaster.j
import QS from "query-string";
import type { ResolvedUri } from "@applets/core/types";
+import { transfer, type WorkerActions } from "@scripts/common";
////////////////////////////////////////////
// 🪟 Applet connecting
@@ -106,7 +108,9 @@ export type BroadcastedApplet = {
setActionHandler(actionId: string, actionHandler: H): void;
};
-export function register(): BroadcastedApplet {
+export function register(
+ options: { worker?: Comlink.Remote } = {},
+): BroadcastedApplet {
const url = new URL(location.href);
const scope = applets.register();
@@ -281,6 +285,12 @@ export function register(): BroadcastedApplet {
},
};
+ if (options.worker !== undefined)
+ context.scope.onworkerport = (event) => {
+ if (!event.port) return;
+ options.worker?.perform(transfer(event.port));
+ };
+
return context;
}
diff --git a/src/scripts/common.ts b/src/scripts/common.ts
index 83e7bbe..78b746e 100644
--- a/src/scripts/common.ts
+++ b/src/scripts/common.ts
@@ -8,6 +8,18 @@ import type { Track } from "@applets/core/types";
// export { SharedWorkerPolyfill as SharedWorker } from "@okikio/sharedworker";
export const SharedWorker = globalThis.SharedWorker;
+////////////////////////////////////////////
+// 🌳
+////////////////////////////////////////////
+
+export type WorkerActions = {
+ perform: ReturnType;
+};
+
+////////////////////////////////////////////
+// 🛠️
+////////////////////////////////////////////
+
export function arrayShuffle(array: Array): Array {
if (array.length === 0) {
return [];
@@ -47,13 +59,13 @@ export function comparable(value: unknown) {
return xxh32(JSON.stringify(value));
}
-export function endpoint>(ini: Comlink.Endpoint) {
+export function endpoint = WorkerActions>(ini: Comlink.Endpoint) {
const e = Comlink.wrap(ini);
if ("start" in ini && typeof ini.start === "function") ini.start();
return e;
}
-export function expose>(actions: T): T {
+export function expose>(actions: A): A {
if (globalThis.SharedWorkerGlobalScope && self instanceof SharedWorkerGlobalScope) {
self.onconnect = (event: MessageEvent) => {
const port = event.ports[0];
@@ -95,6 +107,12 @@ export function jsonEncode(a: T): Uint8Array {
return new TextEncoder().encode(JSON.stringify(a));
}
+export function provide>(actions: A) {
+ return expose({
+ perform: handleWorkerActions(actions),
+ });
+}
+
export async function trackArtworkCacheId(track: Track): Promise {
return await crypto.subtle
.digest("SHA-256", new TextEncoder().encode(track.uri))
@@ -105,3 +123,42 @@ export function transfer(a: T) {
const b = getTransferables(a);
return Comlink.transfer(a, b);
}
+
+// PRIVATE
+
+function handleWorkerActions>(actions: A) {
+ async function handleAction(
+ port: MessagePort,
+ action: {
+ type: "action";
+ id: string;
+ actionId: string;
+ arguments: any;
+ },
+ ) {
+ const result = await actions[action.actionId]?.(action.arguments);
+ return postMessage(port, action.id, result);
+ }
+
+ function postMessage(port: MessagePort, id: string, result: T) {
+ port.postMessage(
+ {
+ type: "actioncomplete",
+ id,
+ result,
+ },
+ {
+ transfer: getTransferables(result),
+ },
+ );
+ }
+
+ return (port: MessagePort) => {
+ port.onmessage = async (message) => {
+ switch (message.data?.type) {
+ case "action":
+ return handleAction(port, message.data);
+ }
+ };
+ };
+}
diff --git a/src/scripts/processor/artwork/worker.ts b/src/scripts/processor/artwork/worker.ts
index b0b1126..cdc0557 100644
--- a/src/scripts/processor/artwork/worker.ts
+++ b/src/scripts/processor/artwork/worker.ts
@@ -2,7 +2,7 @@ import type { IPicture } from "music-metadata";
import * as IDB from "idb-keyval";
import type { Artwork, ArtworkRequest } from "./types";
-import { expose, transfer } from "@scripts/common";
+import { expose, provide, transfer } from "@scripts/common";
import { IDB_ARTWORK_PREFIX } from "./constants";
import { musicMetadataTags } from "../metadata/common";
import { getTransferables } from "@okikio/transferables";
@@ -13,53 +13,10 @@ let queue: ArtworkRequest[] = [];
////////////////////////////////////////////
// ACTIONS
////////////////////////////////////////////
-const c = expose({
- connect,
-});
-
-export type Actions = typeof c;
-
-const actions: { [key: string]: Function } = {
+provide({
artwork,
supply,
-};
-
-// ⚡️
-
-async function connect(port: MessagePort) {
- port.onmessage = async (message) => {
- switch (message.data?.type) {
- case "action":
- return handleAction(port, message.data);
- }
- };
-}
-
-async function handleAction(
- port: MessagePort,
- action: {
- type: "action";
- id: string;
- actionId: string;
- arguments: any;
- },
-) {
- const result = await actions[action.actionId]?.(action.arguments);
- return postMessage(port, action.id, result);
-}
-
-function postMessage(port: MessagePort, id: string, result: T) {
- port.postMessage(
- {
- type: "actioncomplete",
- id,
- result,
- },
- {
- transfer: getTransferables(result),
- },
- );
-}
+});
// Actions