Releases: mykpono/spreadup
v1.4.0 — Invisible Search, Profile Pics, Publish Fix
What's New
@ Mentions — fully invisible background search
- No more visual jumping: A CSS rule hides LinkedIn's search dropdown before any typing starts. The search happens completely in the background.
- Profile images: Real LinkedIn profile photos now appear in the mention dropdown
- Loading indicator: Shows "Searching LinkedIn..." while results load
- Bold names: Selected mentions insert as Unicode bold (
@𝗙𝗲𝗱𝗼𝗿) for visual clarity
Publishing — fixed after extension reload
Root cause: The window.addEventListener('message', handlePanelMessage) was only added inside createPanel(). After an extension reload, the new content script never called createPanel() (the old panel iframe still existed), so no message listener was active — all panel messages including PUBLISH_POST were silently dropped.
Fix: Message listener is now added in init() (always runs). Content script also reconnects to any existing panel iframe on startup.
v1.3.3 — Fix Publish, Hide Search Flash, Bold Mentions
Fixes
Publishing broken after extension reload
Root cause found: After reloading the extension, the content script is re-injected with panelFrame = null. But the panel iframe from the old script still exists in the DOM. Every message from the panel was silently dropped because event.source !== null?.contentWindow.
Fix: Content script now reconnects to an existing panel iframe if panelFrame is null. Also removes stale iframes when creating a new panel.
@ Mention UX improvements
- Hidden search: LinkedIn's search dropdown is now invisible (opacity: 0) during scraping — no more visual jumping between LinkedIn search and SpreadUp panel
- Bold mentions: Inserted names are now Unicode bold (e.g.,
@𝗙𝗲𝗱𝗼𝗿 𝗭𝘂𝗯𝗿𝘆𝘁𝘀𝗸𝗶) so they stand out as tagged names in the post
Extension reload resilience
bg()helper now catches "Extension context invalidated" and shows a toast instead of crashing
v1.3.2 — Handle Extension Reload Gracefully
Fix
"Extension context invalidated" error — After reloading the extension in chrome://extensions, the old panel iframe's chrome.runtime becomes stale. Now catches this error and shows a toast: "Extension updated — please refresh the LinkedIn page."
Important
After reloading the SpreadUp extension, refresh the LinkedIn page (Cmd+R / F5) for all features to work. This applies to both @ mentions and publishing.
v1.3.1 — Fix @ Mention Result Parsing
Fix
v1.3.0 was scraping LinkedIn's search history instead of actual results.
What was wrong
- When focusing LinkedIn's search bar, history items appear immediately (
[role="option"]) - These contain text like "AuthoredUp recent entity historyAuthoredUp"
- The scraper grabbed these before real results loaded
What's fixed
- Now waits for results containing
•(the separator in real results like "name• 1st • title") - Filters out items containing "recent entity history"
- Filters out "See all results" / "Show all"
- Better name/title parsing: extracts name before first
•, skips connection degree, takes title from remaining parts
v1.3.0 — Working @ Mentions + Verified Publish
What's New
@ Mentions — finally working (new approach)
LinkedIn has fully deprecated their Voyager REST and GraphQL typeahead APIs (all return 404). Their new RSC/SDUI endpoints are session-coupled and can't be called programmatically.
New approach: DOM scraping. When you type @name:
- Content script types the query into LinkedIn's own search bar
- Waits for LinkedIn to render the dropdown results
- Scrapes names and titles from
[role="option"]DOM elements - Clears the search bar and shows results in SpreadUp's dropdown
This is resilient because it uses LinkedIn's own UI — it works regardless of API changes.
Publish flow verified
Tested and confirmed working:
- "Start a post" button found (regular DOM,
div[role="button"]) - Editor opens (
.ql-editorin regular DOM) - Text insertion works via
document.execCommand - "Post" button found (shadow DOM, exact text match)
Technical details
- Removed dependency on
chrome.scripting.executeScriptfor search - Search debounce increased to 300ms (DOM scraping needs more time)
searchInProgresslock prevents concurrent searches
v1.2.5 — Fix @ Mentions (chrome.scripting)
Fix
@ Mentions finally working
Previous approaches all failed for specific technical reasons:
- Content script fetch — runs in extension's isolated origin, LinkedIn cookies not sent
- Background service worker fetch —
Cookieis a forbidden header in Fetch spec, silently ignored - Inline script injection — blocked by LinkedIn's Content Security Policy
Solution: chrome.scripting.executeScript with world: 'MAIN' — Chrome injects the search function directly into LinkedIn's page JS context. Full cookie/session access, bypasses CSP entirely.
Changes
- Added
scriptingpermission to manifest - Background script now uses
chrome.scripting.executeScriptto search LinkedIn's Voyager typeahead API in the page's main world - Panel calls background directly via
chrome.runtime.sendMessage— no content script relay needed - Cleaned up unused search code from content script
v1.2.4 — Fix @ Mentions & Publish
Fixes
@ Mentions — new search approach
- Content script now fetches LinkedIn's Voyager API directly (same-origin request from linkedin.com, cookies sent automatically)
- Falls back to background script (chrome.cookies API) if direct fetch fails
- Previous approaches failed because: page-context script injection was blocked by LinkedIn's CSP, and background service worker fetch couldn't authenticate properly
Publish flow — more robust button finding
- "Start a post" button: now tries exact match, then partial text match (case-insensitive)
- "Post" button: now tries exact match, then falls back to finding buttons containing "post" text
- Handles LinkedIn UI variations where button text may differ slightly
v1.2.3 — Fix @ Mention Search
Fix
@ mention search now works — LinkedIn's Content Security Policy was silently blocking the inline script injection from v1.2.2.
What changed
- Panel now calls
chrome.runtime.sendMessagedirectly to the background service worker - Background script uses
chrome.cookiesAPI to get LinkedIn's JSESSIONID and li_at tokens for authenticated Voyager API calls - Removed the broken content-script-to-page-script relay chain
How it works now
- Type
@in editor → panel detects it - Panel sends
SEARCH_LINKEDINmessage directly to background script (150ms debounce) - Background script fetches LinkedIn's typeahead API with proper cookie auth
- Results (5–7 people/companies) render in the dropdown immediately
v1.2.2 — Real-time @ Mentions
What's New
Real-time @ Mention Search
- Type @ in the editor and LinkedIn search results appear in near real-time (150ms debounce)
- Shows 5–7 real LinkedIn people/company results as you type
- Arrow key navigation (↑/↓) and Enter/click to select
- Manual "@name" insert option always available at the bottom of the dropdown
Technical Fix
- Rewrote LinkedIn typeahead search to use page-context script injection instead of content script fetch
- Content scripts run in Chrome's isolated world and can't access LinkedIn's session cookies — the new approach injects a
<script>into the actual LinkedIn page where it has full cookie/auth access - This finally resolves the persistent "@ search returns no results" bug from v1.1.1–v1.2.1
Full Changelog
src/content.js: Replaced isolated-world fetch with page-contextpostMessagebridge for LinkedIn Voyager API callspanel/panel.js: New mention dropdown with search results, avatar initials, titles, keyboard navigation, and click handling
v1.2.1 — Fix Publish Flow (Again)
Bug Fix — Publishing Restored
Root Cause
The v1.1.3 "smart" Post button finder used btn.closest('[role="dialog"]') to prefer buttons inside the composer modal. But closest() cannot traverse shadow DOM boundaries — so it always returned null, and the fallback picked the wrong button or no button.
Fix
Reverted to the original simple approach that was working in v1.0.0:
shadowFindByText('button', 'Post')This finds the button with exact text "Post" inside LinkedIn's shadow DOM and clicks it.