A music player that connects to your cloud/distributed storage.
0
fork

Configure Feed

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

fix: output fallback + s3

+43 -19
+2 -2
deno.jsonc
··· 13 13 "@automerge/automerge-repo": "npm:@automerge/automerge-repo@^2.5.1", 14 14 "@automerge/automerge-repo-network-broadcastchannel": "npm:@automerge/automerge-repo-network-broadcastchannel@^2.5.1", 15 15 "@automerge/automerge-repo-storage-indexeddb": "npm:@automerge/automerge-repo-storage-indexeddb@^2.5.1", 16 - "@bradenmacdonald/s3-lite-client": "jsr:@bradenmacdonald/s3-lite-client@^0.9.4", 16 + "@bradenmacdonald/s3-lite-client": "jsr:@bradenmacdonald/s3-lite-client@^0.9.5", 17 17 "@char/cbor": "jsr:@char/cbor@^0.1.4", 18 18 "@codemirror/autocomplete": "npm:@codemirror/autocomplete@^6.20.0", 19 19 "@codemirror/lang-css": "npm:@codemirror/lang-css@^6.3.1", ··· 22 22 "@fcrozatier/htmlcrunch": "jsr:@fcrozatier/htmlcrunch@^1.5.1", 23 23 "@fry69/deep-diff": "jsr:@fry69/deep-diff@^0.1.10", 24 24 "@js-temporal/polyfill": "npm:@js-temporal/polyfill@^0.5.1", 25 - "@kunkun/kkrpc": "jsr:@kunkun/kkrpc@^0.6.0", 25 + "@kunkun/kkrpc": "jsr:@kunkun/kkrpc@0.6.0", 26 26 "@mary/ds-queue": "jsr:@mary/ds-queue@^0.1.3", 27 27 "@okikio/transferables": "jsr:@okikio/transferables@^1.0.2", 28 28 "@orama/orama": "npm:@orama/orama@^3.1.18",
+4 -1
src/components/configurator/output-fallback/element.js
··· 132 132 let activeOutput = null; 133 133 134 134 for (const output of this.#outputs) { 135 - if (output.ready()) activeOutput = output; 135 + if (output.ready()) { 136 + activeOutput = output; 137 + break; 138 + } 136 139 } 137 140 138 141 this.#activeOutput.value = activeOutput;
+23 -11
src/components/output/bytes/s3/element.js
··· 1 1 import * as IDB from "idb-keyval"; 2 + 2 3 import { BroadcastableDiffuseElement } from "@common/element.js"; 3 4 import { computed, signal } from "@common/signal.js"; 4 5 import { outputManager } from "../../common.js"; ··· 77 78 async connectedCallback() { 78 79 // Broadcast if needed 79 80 if (this.hasAttribute("group")) { 81 + // TODO: Get via leader? 80 82 const actions = this.broadcast(this.nameWithGroup, { 81 83 put: { strategy: "replicate", fn: this.#putIncoming }, 82 84 }); ··· 86 88 } 87 89 } 88 90 89 - // Restore bucket from IndexedDB 91 + // Super 92 + super.connectedCallback(); 93 + 90 94 /** @type {Bucket | undefined} */ 91 95 const stored = await IDB.get(`${STORAGE_PREFIX}/bucket`); 92 96 if (stored) this.#bucket.value = stored; 93 - 94 - // Super 95 - super.connectedCallback(); 96 97 } 97 98 98 99 // BUCKET 99 100 100 101 #bucket = signal(/** @type {Bucket | undefined} */ (undefined)); 101 102 102 - /** @returns {Bucket} */ 103 - get bucket() { 103 + /** @returns {Promise<Bucket | undefined>} */ 104 + async bucket() { 104 105 if (!this.#bucket.value) { 105 - throw new Error("Bucket not set, call setBucket() first."); 106 + /** @type {Bucket | undefined} */ 107 + const stored = await IDB.get(`${STORAGE_PREFIX}/bucket`); 108 + if (stored) this.#bucket.value = stored; 109 + return stored; 106 110 } 107 111 108 112 return this.#bucket.value; ··· 119 123 // GET & PUT 120 124 121 125 /** @param {string} name */ 122 - #getProxy = (name) => 123 - this.proxy.get({ bucket: this.bucket, name: this.#cat(name) }); 126 + #getProxy = async (name) => { 127 + const bucket = await this.bucket(); 128 + if (!bucket) return undefined; 129 + return this.proxy.get({ bucket, name: this.#cat(name) }); 130 + }; 131 + 124 132 #get = this.#getProxy; 125 133 126 134 /** @param {string} name; @param {any} data */ 127 - #putProxy = (name, data) => 128 - this.proxy.put({ bucket: this.bucket, data, name: this.#cat(name) }); 135 + #putProxy = async (name, data) => { 136 + const bucket = await this.bucket(); 137 + if (!bucket) return undefined; 138 + return this.proxy.put({ bucket, data, name: this.#cat(name) }); 139 + }; 140 + 129 141 #put = this.#putProxy; 130 142 131 143 /**
+4 -2
src/components/output/bytes/s3/worker.js
··· 16 16 */ 17 17 export async function get({ bucket, name }) { 18 18 const client = createClient(bucket); 19 - const key = `${OBJECT_PREFIX}${name}`; 19 + const path = bucket.path.replace(/(^\/+|\/+$)/g, ""); 20 + const key = `${path}/${OBJECT_PREFIX}${name}`; 20 21 21 22 try { 22 23 const response = await client.getObject(key); ··· 32 33 */ 33 34 export async function put({ bucket, data, name }) { 34 35 const client = createClient(bucket); 35 - const key = `${OBJECT_PREFIX}${name}`; 36 + const path = bucket.path.replace(/(^\/+|\/+$)/g, ""); 37 + const key = `${path}/${OBJECT_PREFIX}${name}`; 36 38 37 39 await client.putObject(key, data); 38 40 }
+10 -3
src/components/transformer/output/bytes/automerge/element.js
··· 2 2 import { isUint8Array } from "iso-base/utils"; 3 3 4 4 import { computed } from "@common/signal.js"; 5 - import { recursivelyCloneRecords } from "@common/utils.js"; 5 + import { 6 + recursivelyCloneRecords, 7 + removeUndefinedValuesFromRecord, 8 + } from "@common/utils.js"; 6 9 import { OutputTransformer } from "../../base.js"; 7 10 import { 8 11 INITIAL_FACETS_DOCUMENT, ··· 90 93 save: async (newFacets) => { 91 94 const doc = Automerge.change(facetsDocument(), (d) => { 92 95 const clonedCollection = newFacets.map((facet) => { 93 - return recursivelyCloneRecords(facet); 96 + return removeUndefinedValuesFromRecord( 97 + recursivelyCloneRecords(facet), 98 + ); 94 99 }); 95 100 96 101 d.collection = clonedCollection; ··· 122 127 save: async (newThemes) => { 123 128 const doc = Automerge.change(themesDocument(), (d) => { 124 129 const clonedCollection = newThemes.map((theme) => { 125 - return recursivelyCloneRecords(theme); 130 + return removeUndefinedValuesFromRecord( 131 + recursivelyCloneRecords(theme), 132 + ); 126 133 }); 127 134 128 135 d.collection = clonedCollection;