Experiment to rebuild Diffuse using web applets.
1import { xxh32r } from "xxh32/dist/raw.js";
2
3import type { ManagedOutput, Track } from "@applets/core/types";
4import type { DiffuseApplet } from "@scripts/applet/common";
5import { jsonEncode } from "@scripts/common";
6
7export const INITIAL_MANAGED_OUTPUT: ManagedOutput = {
8 tracks: {
9 cacheId: tracksCacheId([]),
10 state: "loading",
11 collection: [],
12 },
13};
14
15export function outputManager<DataType>(args: {
16 context: DiffuseApplet<DataType>;
17 /* Indicate if the initial data loader may proceed. */
18 init?: () => Promise<boolean>;
19 tracks: {
20 get(): Promise<Track[]>;
21 put(tracks: Track[]): Promise<void>;
22 };
23}) {
24 const { context } = args;
25
26 // Initial data loader
27 async function load() {
28 await context.settled();
29
30 if (!context.isMainInstance()) return;
31 if (args.init && (await args.init()) === false) return;
32
33 const collection = await tracks();
34
35 context.data = {
36 ...context.data,
37 tracks: {
38 cacheId: tracksCacheId(collection),
39 state: "loaded",
40 collection,
41 },
42 };
43 }
44
45 load();
46
47 async function tracks(): Promise<Track[]>;
48 async function tracks(tracks: Track[]): Promise<void>;
49 async function tracks(tracks?: Track[]): Promise<Track[] | void> {
50 if (tracks) {
51 // PUT
52 context.data = {
53 ...context.data,
54 tracks: {
55 cacheId: tracksCacheId(tracks),
56 state: "loaded",
57 collection: tracks,
58 },
59 };
60
61 await args.tracks.put(tracks);
62 } else {
63 // GET
64 return await args.tracks.get();
65 }
66 }
67
68 return {
69 load,
70 tracks,
71 };
72}
73
74export function tracksCacheId(tracks: Track[]): string {
75 // TODO: Probably should work with encoded tracks directly?
76 return xxh32r(jsonEncode(tracks)).toString();
77}