[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.

Set nested quotes in dataStore

Grace Kind (Jul 19, 2026, 11:47 PM -0500) ce5b780f 52afb735

+125 -23
+1 -1
package.json
··· 1 1 { 2 2 "name": "impro", 3 - "version": "0.18.27", 3 + "version": "0.18.28", 4 4 "type": "module", 5 5 "scripts": { 6 6 "start": "rm -rf \"${BUILD_DIR:-build}\" && NODE_ENV=development eleventy --serve",
+17 -6
src/js/dataLayer/dataStore.js
··· 64 64 } 65 65 66 66 setPosts(posts) { 67 - for (const post of posts) { 68 - this.$posts.set(post.uri, post); 69 - const quotedPost = getQuotedPost(post); 67 + const seenQuotedPostUris = new Set(); 68 + const setQuotedPost = (quotedPost) => { 70 69 if ( 71 - quotedPost?.$type === "app.bsky.embed.record#viewRecord" && 72 - this.$posts.get(quotedPost.uri) == null 70 + quotedPost?.$type !== "app.bsky.embed.record#viewRecord" || 71 + seenQuotedPostUris.has(quotedPost.uri) 73 72 ) { 74 - this.$posts.set(quotedPost.uri, embedViewRecordToPostView(quotedPost)); 73 + return; 74 + } 75 + seenQuotedPostUris.add(quotedPost.uri); 76 + 77 + const normalizedQuotedPost = embedViewRecordToPostView(quotedPost); 78 + if (this.$posts.get(quotedPost.uri) == null) { 79 + this.$posts.set(quotedPost.uri, normalizedQuotedPost); 75 80 } 81 + setQuotedPost(getQuotedPost(normalizedQuotedPost)); 82 + }; 83 + 84 + for (const post of posts) { 85 + this.$posts.set(post.uri, post); 86 + setQuotedPost(getQuotedPost(post)); 76 87 } 77 88 } 78 89
+1 -1
src/js/dataLayer/mutations.js
··· 1000 1000 for (const post of hydratedPosts) { 1001 1001 // NOTE: LEXICON DEVIATION 1002 1002 post.viewer.priorityReply = true; 1003 - this.dataStore.$posts.set(post.uri, post); 1004 1003 } 1004 + this.dataStore.setPosts(hydratedPosts); 1005 1005 const rootPost = hydratedPosts[0]; 1006 1006 // If it's a reply, update the reply post thread in the store 1007 1007 if (replyTo) {
-15
src/js/identityPrecaching.js
··· 1 - import { getQuotedPost } from "/js/dataHelpers.js"; 2 1 import { effect, untrack } from "/js/signals.js"; 3 2 4 3 export function setUpIdentityPrecaching(dataLayer, identityResolver) { ··· 20 19 setDid(post.author); 21 20 } catch (error) { 22 21 console.error("error when setting DID from post", post); 23 - console.error(error); 24 - } 25 - try { 26 - const quotedPost = getQuotedPost(post); 27 - if (quotedPost) { 28 - setDid(quotedPost.author); 29 - // TODO - normalize quoted posts? 30 - const nestedQuotedPost = getQuotedPost(quotedPost); 31 - if (nestedQuotedPost) { 32 - setDid(nestedQuotedPost.author); 33 - } 34 - } 35 - } catch (error) { 36 - console.error("error when setting DID from quoted post", post); 37 22 console.error(error); 38 23 } 39 24 }
+63
tests/unit/specs/dataLayer/dataStore.test.js
··· 30 30 dataStoreB.$posts.get(post.uri), 31 31 ); 32 32 }); 33 + 34 + it("should normalize nested quoted posts", () => { 35 + const dataStore = new DataStore(); 36 + const nestedQuotedPost = { 37 + $type: "app.bsky.embed.record#viewRecord", 38 + uri: "at://did:test/app.bsky.feed.post/nested", 39 + cid: "nested-cid", 40 + author: { did: "did:test", handle: "nested.test" }, 41 + value: { text: "nested" }, 42 + indexedAt: "2026-07-19T00:00:00Z", 43 + }; 44 + const quotedPost = { 45 + $type: "app.bsky.embed.record#viewRecord", 46 + uri: "at://did:test/app.bsky.feed.post/quoted", 47 + cid: "quoted-cid", 48 + author: { did: "did:test", handle: "quoted.test" }, 49 + value: { text: "quoted" }, 50 + embeds: [ 51 + { 52 + $type: "app.bsky.embed.record#view", 53 + record: nestedQuotedPost, 54 + }, 55 + ], 56 + indexedAt: "2026-07-19T00:00:00Z", 57 + }; 58 + const post = { 59 + uri: "at://did:test/app.bsky.feed.post/root", 60 + record: { text: "root" }, 61 + embed: { 62 + $type: "app.bsky.embed.record#view", 63 + record: quotedPost, 64 + }, 65 + }; 66 + 67 + dataStore.setPosts([post]); 68 + 69 + assert.deepEqual(dataStore.$posts.get(quotedPost.uri), { 70 + uri: quotedPost.uri, 71 + cid: quotedPost.cid, 72 + author: quotedPost.author, 73 + record: quotedPost.value, 74 + embed: quotedPost.embeds[0], 75 + labels: undefined, 76 + likeCount: undefined, 77 + replyCount: undefined, 78 + repostCount: undefined, 79 + quoteCount: undefined, 80 + indexedAt: quotedPost.indexedAt, 81 + }); 82 + assert.deepEqual(dataStore.$posts.get(nestedQuotedPost.uri), { 83 + uri: nestedQuotedPost.uri, 84 + cid: nestedQuotedPost.cid, 85 + author: nestedQuotedPost.author, 86 + record: nestedQuotedPost.value, 87 + embed: undefined, 88 + labels: undefined, 89 + likeCount: undefined, 90 + replyCount: undefined, 91 + repostCount: undefined, 92 + quoteCount: undefined, 93 + indexedAt: nestedQuotedPost.indexedAt, 94 + }); 95 + }); 33 96 }); 34 97 35 98 describe("setConvo", () => {
+43
tests/unit/specs/identityPrecaching.test.js
··· 50 50 assert.deepEqual(resolvedHandles.get("carol.test"), "did:plc:carol"); 51 51 }); 52 52 }); 53 + 54 + describe("post precaching", () => { 55 + it("should cache identities for posts normalized from nested quotes", async () => { 56 + const { dataStore, dataLayer, identityResolver, resolvedHandles } = setup(); 57 + setUpIdentityPrecaching(dataLayer, identityResolver); 58 + 59 + const nestedQuote = { 60 + $type: "app.bsky.embed.record#viewRecord", 61 + uri: "at://did:plc:nested/app.bsky.feed.post/1", 62 + author: { handle: "nested.test", did: "did:plc:nested" }, 63 + value: { text: "nested quote" }, 64 + }; 65 + const quote = { 66 + $type: "app.bsky.embed.record#viewRecord", 67 + uri: "at://did:plc:quote/app.bsky.feed.post/1", 68 + author: { handle: "quote.test", did: "did:plc:quote" }, 69 + value: { text: "quote" }, 70 + embeds: [ 71 + { 72 + $type: "app.bsky.embed.record#view", 73 + record: nestedQuote, 74 + }, 75 + ], 76 + }; 77 + 78 + dataStore.setPosts([ 79 + { 80 + uri: "at://did:plc:root/app.bsky.feed.post/1", 81 + author: { handle: "root.test", did: "did:plc:root" }, 82 + record: { text: "root" }, 83 + embed: { 84 + $type: "app.bsky.embed.record#view", 85 + record: quote, 86 + }, 87 + }, 88 + ]); 89 + await flushEffects(); 90 + 91 + assert.deepEqual(resolvedHandles.get("root.test"), "did:plc:root"); 92 + assert.deepEqual(resolvedHandles.get("quote.test"), "did:plc:quote"); 93 + assert.deepEqual(resolvedHandles.get("nested.test"), "did:plc:nested"); 94 + }); 95 + });