[READ-ONLY] Mirror of https://github.com/improsocial/impro An extensible Bluesky client for web impro.social
6

Configure Feed

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

Cache plugin style 404s

Grace Kind (Jul 18, 2026, 8:31 PM -0500) dc9c158a 14529270

+43 -13
+1 -1
package.json
··· 1 1 { 2 2 "name": "impro", 3 - "version": "0.18.11", 3 + "version": "0.18.12", 4 4 "type": "module", 5 5 "scripts": { 6 6 "start": "rm -rf \"${BUILD_DIR:-build}\" && NODE_ENV=development eleventy --serve",
+8 -6
src/js/plugins/pluginCache.js
··· 8 8 return await caches.open(CACHE_NAME); 9 9 } 10 10 11 - async fetch(url) { 11 + async fetch(url, { doCacheNotFound = false } = {}) { 12 12 const cache = await this._getCache(); 13 13 let response = await cache.match(url); 14 14 if (!response) { 15 15 response = await fetch(url, { redirect: "follow" }); 16 - if (!response.ok) { 17 - const error = new Error(`HTTP ${response.status} ${url}`); 18 - error.status = response.status; 19 - throw error; 16 + if (response.ok || (doCacheNotFound && response.status === 404)) { 17 + await cache.put(url, response.clone()); 20 18 } 21 - await cache.put(url, response.clone()); 19 + } 20 + if (!response.ok) { 21 + const error = new Error(`HTTP ${response.status} ${url}`); 22 + error.status = response.status; 23 + throw error; 22 24 } 23 25 return response; 24 26 }
+3 -1
src/js/plugins/sourceProvider.js
··· 96 96 } 97 97 const url = remoteAssetUrl({ repo, file: "styles.css", release: version }); 98 98 try { 99 - const response = await this.pluginCache.fetch(url); 99 + const response = await this.pluginCache.fetch(url, { 100 + doCacheNotFound: true, 101 + }); 100 102 return await response.text(); 101 103 } catch (error) { 102 104 if (error?.status === 404) return null;
+25
tests/unit/specs/plugins/pluginCache.test.js
··· 130 130 const bucket = await cachesStub.caches.open("plugins-v1"); 131 131 assert.deepEqual((await bucket.keys()).length, 0); 132 132 }); 133 + 134 + it("caches 404s with doCacheNotFound and skips refetching them", async () => { 135 + fetchStub = stubFetch(async () => 136 + makeResponse("nope", { ok: false, status: 404 }), 137 + ); 138 + const cache = new PluginCache(); 139 + const url = "https://example.test/styles.css"; 140 + await assert.rejects(cache.fetch(url, { doCacheNotFound: true }), /404/); 141 + const error = await cache 142 + .fetch(url, { doCacheNotFound: true }) 143 + .then(null, (thrown) => thrown); 144 + assert.deepEqual(error.status, 404); 145 + assert.deepEqual(fetchStub.calls.length, 1); 146 + }); 147 + 148 + it("does not cache non-404 errors even with doCacheNotFound", async () => { 149 + fetchStub = stubFetch(async () => 150 + makeResponse("boom", { ok: false, status: 500 }), 151 + ); 152 + const cache = new PluginCache(); 153 + const url = "https://example.test/styles.css"; 154 + await assert.rejects(cache.fetch(url, { doCacheNotFound: true }), /500/); 155 + await assert.rejects(cache.fetch(url, { doCacheNotFound: true }), /500/); 156 + assert.deepEqual(fetchStub.calls.length, 2); 157 + }); 133 158 }); 134 159 135 160 describe("PluginCache.reconcile", () => {
+6 -5
tests/unit/specs/sourceProvider.test.js
··· 40 40 const calls = []; 41 41 return { 42 42 calls, 43 - async fetch(url) { 44 - calls.push(url); 43 + async fetch(url, options) { 44 + calls.push({ url, options }); 45 45 return handler(url); 46 46 }, 47 47 }; ··· 159 159 const provider = new SourceProvider(pluginCache); 160 160 const manifest = await provider.getManifest("alpha", "1.0.0", "ow/alpha"); 161 161 assert.deepEqual( 162 - pluginCache.calls[0], 162 + pluginCache.calls[0].url, 163 163 "https://raw.githubusercontent.com/ow/alpha/refs/tags/1.0.0/manifest.json", 164 164 ); 165 165 assert.deepEqual(manifest.id, "alpha"); ··· 176 176 const provider = new SourceProvider(pluginCache); 177 177 const source = await provider.getSource("alpha", "2.5.0", "ow/alpha"); 178 178 assert.deepEqual( 179 - pluginCache.calls[0], 179 + pluginCache.calls[0].url, 180 180 "https://raw.githubusercontent.com/ow/alpha/refs/tags/2.5.0/main.js", 181 181 ); 182 182 assert.deepEqual(source, "alert(1)"); ··· 236 236 const provider = new SourceProvider(pluginCache); 237 237 const styles = await provider.getStyles("alpha", "1.0.0", "ow/alpha"); 238 238 assert.deepEqual( 239 - pluginCache.calls[0], 239 + pluginCache.calls[0].url, 240 240 "https://raw.githubusercontent.com/ow/alpha/refs/tags/1.0.0/styles.css", 241 241 ); 242 + assert.deepEqual(pluginCache.calls[0].options, { doCacheNotFound: true }); 242 243 assert.deepEqual(styles, "body{color:blue}"); 243 244 }); 244 245