') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); feat: Ask all vite-aim servers to forget the import map by webJose · Pull Request #31 · collagejs/imo · GitHub
Skip to content

feat: Ask all vite-aim servers to forget the import map - #31

Merged
webJose merged 4 commits into
mainfrom
JP/aim-delete-im
Jul 11, 2026
Merged

feat: Ask all vite-aim servers to forget the import map#31
webJose merged 4 commits into
mainfrom
JP/aim-delete-im

Conversation

@webJose

@webJosewebJose commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Closes#22.

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends @collagejs/imo to proactively request import-map deletion from discovered/allowed Vite dev servers before reloading the app, and refactors the IMo runtime entry to a separate implementation module while adding UI pieces to show server-action progress.

Changes:

  • Track discovered dev-server origins in session storage and add helpers to filter “involved” (allowed) servers.
  • Add a “delete import map then reload” flow in the widget UI, including progress and countdown messaging.
  • Extract the IMo runtime logic from src/imo/imo.ts into a new src/imo/imo-impl.ts.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
vite.config.tsPasses a new importMapTimeout option into the Vite CSS plugin configuration.
src/shared/storage-keys.tsAdds a session-storage key for discovered Vite servers and includes it in the “vite-servers” delete path.
src/shared/common.tsAdds helpers to read discovered servers from session storage and compute the allowed/excluded server sets.
src/private-types.tsIntroduces HttpOrigin branded string type used for server-origin handling.
src/lib/Imo/TimerMessage.svelteNew timer-driven message component used for delayed reload behavior.
src/lib/Imo/Spinner.svelteNew loading indicator used in server-action progress UI.
src/lib/Imo/ServerActionProgress.svelteNew component to display per-server POST/DELETE progress and results.
src/lib/Imo/ImoDialog.svelteRefactors dialog to use DialogContent and switch to DeleteAndReload flow on save.
src/lib/Imo/DialogContent.svelteExtracted tabbed content (Current/Original/Dev Servers) from ImoDialog.
src/lib/Imo/DeleteAndReload.svelteNew component that issues DELETE requests to involved servers and reloads (or prompts) based on results.
src/lib/Imo/CurrentImportMap.svelteTrims override input values and preserves existing replacement text when editing/accepting.
src/imo/imo.tsSimplifies entrypoint to call main() from the new implementation module.
src/imo/imo-impl.tsNew implementation module; now persists discovered servers to session storage and shares filtering logic.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment threadsrc/lib/Imo/ServerActionProgress.svelte
Comment threadsrc/lib/Imo/ServerActionProgress.svelte Outdated
Comment threadsrc/lib/Imo/DeleteAndReload.svelte
Comment threadsrc/lib/Imo/TimerMessage.svelte Outdated
Comment threadsrc/shared/common.ts
Comment threadsrc/private-types.ts
- Also fixed a race condition by eliminating the use of Promise.all() for "overall done" state
@webJose
webJose merged commit 7ca5259 into mainJul 11, 2026
1 check passed
@webJose
webJose deleted the JP/aim-delete-im branch July 11, 2026 03:20
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ask @collagejs/vite-aim to delete the import map before reloading due to override changes

2 participants

@webJose