Skip to content

Releases: mykpono/spreadup

v1.4.0 — Invisible Search, Profile Pics, Publish Fix

13 Apr 04:35

Choose a tag to compare

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

13 Apr 04:24

Choose a tag to compare

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

13 Apr 04:19

Choose a tag to compare

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

13 Apr 04:17

Choose a tag to compare

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

13 Apr 04:07

Choose a tag to compare

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:

  1. Content script types the query into LinkedIn's own search bar
  2. Waits for LinkedIn to render the dropdown results
  3. Scrapes names and titles from [role="option"] DOM elements
  4. 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-editor in regular DOM)
  • Text insertion works via document.execCommand
  • "Post" button found (shadow DOM, exact text match)

Technical details

  • Removed dependency on chrome.scripting.executeScript for search
  • Search debounce increased to 300ms (DOM scraping needs more time)
  • searchInProgress lock prevents concurrent searches

v1.2.5 — Fix @ Mentions (chrome.scripting)

13 Apr 03:55

Choose a tag to compare

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 fetchCookie is 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 scripting permission to manifest
  • Background script now uses chrome.scripting.executeScript to 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

13 Apr 03:50

Choose a tag to compare

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

13 Apr 03:45

Choose a tag to compare

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.sendMessage directly to the background service worker
  • Background script uses chrome.cookies API 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

  1. Type @ in editor → panel detects it
  2. Panel sends SEARCH_LINKEDIN message directly to background script (150ms debounce)
  3. Background script fetches LinkedIn's typeahead API with proper cookie auth
  4. Results (5–7 people/companies) render in the dropdown immediately

v1.2.2 — Real-time @ Mentions

13 Apr 03:41

Choose a tag to compare

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-context postMessage bridge for LinkedIn Voyager API calls
  • panel/panel.js: New mention dropdown with search results, avatar initials, titles, keyboard navigation, and click handling

v1.2.1 — Fix Publish Flow (Again)

13 Apr 03:36

Choose a tag to compare

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.