fix: address Copilot review on release/3.3.2
Non-ASCII glyphs (regression of the #681 class of Windows UnicodeEncodeError): - mempalace/cli.py: "✗" → "ERROR:", "⚠" → "WARNING:", em dash → "-" - mempalace/sweeper.py: "⚠" → "WARNING:" Backend arg validation: - mempalace/backends/chroma.py: `_normalize_get_collection_args` now raises TypeError on unexpected trailing positional args instead of silently dropping them — surfaces call-site bugs early. Docs site: - website/.vitepress/config.mts: gate Google Analytics scripts behind MEMPALACE_DOCS_GA_ID env var (default off). Self-hosters no longer get GA injected unconditionally. Landing page SPA hygiene: - website/.vitepress/theme/landing/useLandingEffects.js: collect all IntersectionObserver disconnects and removeEventListener thunks in a shared `cleanups` registry; drain it in `onBeforeUnmount` so observers and form/replay listeners don't leak across SPA navigations.
This commit is contained in:
@@ -11,6 +11,7 @@ function normalizeBase(base?: string): string {
|
||||
|
||||
const docsBase = normalizeBase(process.env.DOCS_BASE || '/')
|
||||
const editBranch = process.env.DOCS_EDIT_BRANCH || 'main'
|
||||
const gaId = process.env.MEMPALACE_DOCS_GA_ID
|
||||
|
||||
export default withMermaid(
|
||||
defineConfig({
|
||||
@@ -26,8 +27,10 @@ export default withMermaid(
|
||||
['meta', { property: 'og:title', content: 'MemPalace — AI Memory System' }],
|
||||
['meta', { property: 'og:description', content: '96.6% LongMemEval recall. Zero API calls. Local, free, open source.' }],
|
||||
['meta', { property: 'og:image', content: `${docsBase}mempalace_logo.png` }],
|
||||
['script', { async: '', src: 'https://www.googletagmanager.com/gtag/js?id=G-PPQE4Z7P1K' }],
|
||||
['script', {}, `window.dataLayer = window.dataLayer || [];\nfunction gtag(){dataLayer.push(arguments);}\ngtag('js', new Date());\ngtag('config', 'G-PPQE4Z7P1K');`],
|
||||
...(gaId ? [
|
||||
['script', { async: '', src: `https://www.googletagmanager.com/gtag/js?id=${gaId}` }],
|
||||
['script', {}, `window.dataLayer = window.dataLayer || [];\nfunction gtag(){dataLayer.push(arguments);}\ngtag('js', new Date());\ngtag('config', '${gaId}');`],
|
||||
] as const : []),
|
||||
],
|
||||
|
||||
themeConfig: {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { onMounted, onBeforeUnmount } from 'vue'
|
||||
|
||||
export function useLandingEffects() {
|
||||
// Shared cleanup registry — IIFEs push disconnect/removeEventListener thunks
|
||||
// here so onBeforeUnmount can tear everything down on SPA nav.
|
||||
const cleanups = []
|
||||
|
||||
onMounted(() => {
|
||||
if (typeof document === 'undefined') return
|
||||
|
||||
@@ -25,7 +29,7 @@ onMounted(() => {
|
||||
if (text != null) msg.textContent = text
|
||||
}
|
||||
|
||||
form.addEventListener('submit', async (e) => {
|
||||
const onSubmit = async (e) => {
|
||||
e.preventDefault()
|
||||
if (form.classList.contains('is-success') || form.classList.contains('is-pending')) return
|
||||
|
||||
@@ -70,11 +74,17 @@ onMounted(() => {
|
||||
button.disabled = false
|
||||
input.disabled = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Clear error state as soon as the user edits
|
||||
input.addEventListener('input', () => {
|
||||
const onInput = () => {
|
||||
if (form.classList.contains('is-error')) setState(null, '')
|
||||
}
|
||||
|
||||
form.addEventListener('submit', onSubmit)
|
||||
input.addEventListener('input', onInput)
|
||||
cleanups.push(() => {
|
||||
form.removeEventListener('submit', onSubmit)
|
||||
input.removeEventListener('input', onInput)
|
||||
})
|
||||
})
|
||||
})()
|
||||
@@ -102,6 +112,7 @@ onMounted(() => {
|
||||
})
|
||||
}, { rootMargin: '0px 0px -80px 0px' })
|
||||
items.forEach(el => io.observe(el))
|
||||
cleanups.push(() => io.disconnect())
|
||||
})()
|
||||
|
||||
/* ---------- Forgetting demo ---------- */
|
||||
@@ -369,17 +380,27 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
if (replayBtn) replayBtn.addEventListener('click', () => {
|
||||
const onReplayClick = () => {
|
||||
resetAll()
|
||||
armObservers()
|
||||
})
|
||||
}
|
||||
if (replayBtn) replayBtn.addEventListener('click', onReplayClick)
|
||||
|
||||
armObservers()
|
||||
|
||||
cleanups.push(() => {
|
||||
disconnectObservers()
|
||||
if (replayBtn) replayBtn.removeEventListener('click', onReplayClick)
|
||||
})
|
||||
})()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (typeof document === 'undefined') return
|
||||
document.body.classList.remove('mempalace-active')
|
||||
while (cleanups.length) {
|
||||
const fn = cleanups.pop()
|
||||
try { fn() } catch (_) { /* swallow — teardown best-effort */ }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user