this repo has no description
0
fork

Configure Feed

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

fix: normalize image and link markdown in sync's PDS comparison

processNoteContent rewrites local image paths to blob CIDs and internal
markdown links to AT URIs before writing the note to PDS. matchesPDS
was comparing the raw local body against the transformed PDS body, so
any post with an image or internal link in its first 5000 chars failed
the equality check deterministically. sync would then store contentHash
and noteHash as empty strings, and the next publish run would re-flag
the post as "content changed" even though nothing had changed.

Strip image markdown and link URLs from both sides before comparing so
the rewrite asymmetry no longer matters.

+21 -10
+21 -10
packages/remanso-cli/src/commands/sync.ts
··· 25 25 import { exitOnCancel } from "../../../cli/src/lib/prompts.ts"; 26 26 import process from "node:process"; 27 27 28 + // PDS note content has image paths replaced with blob CIDs and internal markdown 29 + // links rewritten to AT URIs (see lib/note.ts processNoteContent). Strip both 30 + // constructs from each side so the comparison is symmetric. 31 + function normalizeNoteBodyForCompare(s: string): string { 32 + return s 33 + .replace(/!\[[^\]]*\]\([^)]*\)/g, "") 34 + .replace(/\[([^\]]+)\]\([^)]+\)/g, "$1"); 35 + } 36 + 28 37 async function matchesPDS( 29 38 localPost: BlogPost, 30 39 doc: ListDocumentsResult, ··· 80 89 return false; 81 90 } 82 91 83 - // Compare note body content up to 5000 chars. 84 - // Beyond that, image paths are transformed to blob links in PDS, 85 - // making direct comparison unreliable without re-uploading images. 92 + // Compare normalized note body up to 5000 chars. Both sides go through 93 + // normalizeNoteBodyForCompare to neutralize the image-path → blob and 94 + // internal-link → at:// rewrites the publish path applies. 86 95 const pdsNoteContent = (noteValue.content as string | undefined) ?? ""; 87 - const localNoteContent = localPost.content.trim(); 88 - const compareLength = Math.min(localNoteContent.length, 5000); 96 + const localNormalized = normalizeNoteBodyForCompare( 97 + localPost.content.trim(), 98 + ); 99 + const pdsNormalized = normalizeNoteBodyForCompare(pdsNoteContent); 100 + const compareLength = Math.min(localNormalized.length, 5000); 89 101 if ( 90 102 compareLength > 0 && 91 - pdsNoteContent.slice(0, compareLength) !== 92 - localNoteContent.slice(0, compareLength) 103 + pdsNormalized.slice(0, compareLength) !== 104 + localNormalized.slice(0, compareLength) 93 105 ) { 94 106 return false; 95 107 } ··· 161 173 process.exit(1); 162 174 } 163 175 164 - const { config, configPath: resolvedConfigPath } = await loadConfig( 165 - configPath, 166 - ); 176 + const { config, configPath: resolvedConfigPath } = 177 + await loadConfig(configPath); 167 178 const configDir = path.dirname(resolvedConfigPath); 168 179 169 180 log.info(`Publication: ${config.publicationUri}`);