Experiment to rebuild Diffuse using web applets.
0

Configure Feed

Select the types of activity you want to include in your feed.

wip

+89 -19
+3
astro.config.js
··· 11 11 }, 12 12 vite: { 13 13 plugins: [wasm()], 14 + server: { 15 + hmr: false, 16 + }, 14 17 }, 15 18 });
+1
deno.lock
··· 41 41 "npm:sass@^1.87.0", 42 42 "npm:spellcaster@6", 43 43 "npm:throttle-debounce@^5.0.2", 44 + "npm:uint8arrays@^5.1.0", 44 45 "npm:uri-js@^4.4.1", 45 46 "npm:vite-plugin-wasm@^3.4.1", 46 47 "npm:webamp@^1.5.0",
+16
package-lock.json
··· 20 20 "query-string": "^9.1.2", 21 21 "spellcaster": "^6.0.0", 22 22 "throttle-debounce": "^5.0.2", 23 + "uint8arrays": "^5.1.0", 23 24 "uri-js": "^4.4.1", 24 25 "webamp": "^1.5.0", 25 26 "xxh32": "^2.0.5" ··· 4876 4877 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 4877 4878 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 4878 4879 }, 4880 + "node_modules/multiformats": { 4881 + "version": "13.3.6", 4882 + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.3.6.tgz", 4883 + "integrity": "sha512-yakbt9cPYj8d3vi/8o/XWm61MrOILo7fsTL0qxNx6zS0Nso6K5JqqS2WV7vK/KSuDBvrW3KfCwAdAgarAgOmww==", 4884 + "license": "Apache-2.0 OR MIT" 4885 + }, 4879 4886 "node_modules/music-metadata": { 4880 4887 "version": "11.2.3", 4881 4888 "resolved": "https://registry.npmjs.org/music-metadata/-/music-metadata-11.2.3.tgz", ··· 6478 6485 }, 6479 6486 "funding": { 6480 6487 "url": "https://github.com/sponsors/sindresorhus" 6488 + } 6489 + }, 6490 + "node_modules/uint8arrays": { 6491 + "version": "5.1.0", 6492 + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.0.tgz", 6493 + "integrity": "sha512-vA6nFepEmlSKkMBnLBaUMVvAC4G3CTmO58C12y4sq6WPDOR7mOFYOi7GlrQ4djeSbP6JG9Pv9tJDM97PedRSww==", 6494 + "license": "Apache-2.0 OR MIT", 6495 + "dependencies": { 6496 + "multiformats": "^13.0.0" 6481 6497 } 6482 6498 }, 6483 6499 "node_modules/ultrahtml": {
+1
package.json
··· 15 15 "query-string": "^9.1.2", 16 16 "spellcaster": "^6.0.0", 17 17 "throttle-debounce": "^5.0.2", 18 + "uint8arrays": "^5.1.0", 18 19 "uri-js": "^4.4.1", 19 20 "webamp": "^1.5.0", 20 21 "xxh32": "^2.0.5"
+6
src/pages/orchestrator/input-cache/_applet.astro
··· 49 49 50 50 await waitUntilAppletIsReady(configurator.input); 51 51 52 + console.log("Ready."); 53 + 52 54 const cachedTracks = orchestrator.output.data.tracks.collection; 53 55 await configurator.input.sendAction("contextualize", cachedTracks); 54 56 57 + console.log("Start list."); 58 + 55 59 const tracks = await configurator.input.sendAction<Track[]>("list", cachedTracks, { 56 60 timeoutDuration: 60000 * 60 * 24, 57 61 }); 62 + 63 + console.log("Got tracks", tracks); 58 64 59 65 // Process 60 66 const tracksWithMetadata = await tracks.reduce(
+50 -16
src/pages/orchestrator/output-management/_applet.astro
··· 2 2 <script> 3 3 import { debounce } from "throttle-debounce"; 4 4 import * as Automerge from "@automerge/automerge"; 5 + import * as Uint8 from "uint8arrays"; 5 6 6 7 import type { Track } from "@applets/core/types.d.ts"; 7 8 import type { State } from "./types.d.ts"; 8 9 import { applet, register, waitUntilAppletIsReady } from "@scripts/applets/common"; 9 10 11 + type TracksDoc = { collection: Track[] }; 12 + 13 + const TRACKS_INITIAL_DOC = Automerge.load<TracksDoc>( 14 + Uint8.fromString( 15 + "hW9Kg5qsIsEAeAEQkb+c0IkXTSWyGqZ6jXtFxgETwM42fL3CMN78UZ4Qa3a9RfOrJu5qKzlM7IxwAUXelQYBAgMCEwIjBkACVgIHFQwhAiMCNAFCAlYCgAECfwB/AX8Bf+ub7MEGfwB/B38KY29sbGVjdGlvbn8AfwEBfwJ/AH8AAA", 16 + "base64", 17 + ), 18 + ); 19 + 10 20 //////////////////////////////////////////// 11 21 // SETUP 12 22 //////////////////////////////////////////// 13 23 const context = register<State>(); 14 24 25 + // Data codec 26 + const codec = { 27 + decode(data: any) { 28 + return { 29 + hasSyncedTracks: data.hasSyncedTracks, 30 + ready: context.data.ready, 31 + tracks: Automerge.load<TracksDoc>(data.tracks), 32 + }; 33 + }, 34 + 35 + encode(data: State) { 36 + return { 37 + hasSyncedTracks: true, 38 + ready: context.data.ready, 39 + tracks: Automerge.save(data.tracks), 40 + }; 41 + }, 42 + }; 43 + 44 + context.codec = codec; 45 + 15 46 // Initial data 16 47 context.data = { 17 - tracks: Automerge.from({ collection: [] }), 48 + // Empty tracks collection, DO NOT CHANGE. 49 + // (avoids the initial sync problem with Automerge) 50 + tracks: TRACKS_INITIAL_DOC, 18 51 19 52 hasSyncedTracks: false, 20 53 ··· 29 62 // Load tracks if needed 30 63 if (context.isMainInstance()) 31 64 loadTracks().then((doc) => { 65 + console.log("LOADED DOC", doc); 66 + 32 67 if (doc) { 33 - const mergedDoc = Automerge.merge(doc, context.data.tracks); 68 + const mergedDoc = Automerge.merge(context.data.tracks, doc); 69 + console.log("MERGED DOC", doc); 34 70 update({ tracks: mergedDoc }); 35 71 } 36 72 ··· 42 78 context.data = { ...context.data, ...partial }; 43 79 } 44 80 45 - function updateTracks(tracks: Track[]): Automerge.Doc<{ collection: Track[] }> { 81 + function updateTracks(tracks: Track[]): Automerge.Doc<TracksDoc> { 46 82 console.log(context.data.tracks); 83 + console.log(context.isMainInstance()); 47 84 48 85 const doc = Automerge.change(context.data.tracks, (d) => { 49 86 d.collection = cleanUndefinedValuesForTracks(tracks); ··· 76 113 return undefined; 77 114 } 78 115 79 - return Automerge.load<{ collection: Track[] }>(data as Uint8Array); 116 + return Automerge.load<TracksDoc>(data as Uint8Array); 80 117 } 81 118 82 119 //////////////////////////////////////////// ··· 92 129 saveTracksToOutput(doc); 93 130 }; 94 131 95 - const saveTracksToOutput = debounce( 96 - 5000, 97 - async function (doc: Automerge.Doc<{ collection: Track[] }>) { 98 - const data = Automerge.save(doc); 132 + const saveTracksToOutput = debounce(5000, async function (doc: Automerge.Doc<TracksDoc>) { 133 + const data = Automerge.save(doc); 99 134 100 - console.log("🔮 Saving tracks"); 135 + console.log("🔮 Saving tracks"); 101 136 102 - await configurator.output.sendAction("put", { 103 - name: "tracks.json", 104 - data, 105 - }); 137 + await configurator.output.sendAction("put", { 138 + name: "tracks.json", 139 + data, 140 + }); 106 141 107 - console.log("🔮 Tracks saved to output"); 108 - }, 109 - ); 142 + console.log("🔮 Tracks saved to output"); 143 + }); 110 144 111 145 context.setActionHandler("tracks", tracksHandler); 112 146
+12 -3
src/scripts/applets/common.ts
··· 93 93 if (event.data === "PING") { 94 94 channel.postMessage("PONG"); 95 95 } else if (event.data?.type === "data") { 96 - scope.data = event.data.data; 96 + scope.data = context.codec.decode(event.data.data); 97 97 } else if (waitingForPong && event.data === "PONG") { 98 98 waitingForPong = false; 99 99 isMainInstance = false; ··· 115 115 if (isMainInstance) { 116 116 channel.postMessage({ 117 117 type: "data", 118 - data: event.data, 118 + data: context.codec.encode(event.data), 119 119 }); 120 120 } 121 121 }; 122 122 123 - return { 123 + const context = { 124 + scope, 125 + 124 126 get id() { 125 127 return id; 126 128 }, ··· 133 135 scope.data = data; 134 136 }, 135 137 138 + codec: { 139 + decode: (data: any) => data as DataType, 140 + encode: (data: DataType) => data as any, 141 + }, 142 + 136 143 isMainInstance() { 137 144 return isMainInstance; 138 145 }, ··· 166 173 scope.setActionHandler(actionId, handler); 167 174 }, 168 175 }; 176 + 177 + return context; 169 178 } 170 179 171 180 ////////////////////////////////////////////