fix(sqlite,browser): resolve SQLite connection pool deadlock, disable stale SW cache, and update BRAIN.md
MindSift CI & Docker Release / Build, Test in Container & Push (push) Failing after 38s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Failing after 38s
This commit is contained in:
1 parent
d6bc2976d9
commit
5c4e130862
8 files changed
+414
-231
No files matched your search
+6
-3
@@ -15,10 +15,13 @@
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
<script>
|
||||
if ('caches' in window) {
|
||||
caches.keys().then((keys) => keys.forEach((k) => caches.delete(k))).catch(() => {});
|
||||
}
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.register('/sw.js').catch(() => {});
|
||||
});
|
||||
navigator.serviceWorker.getRegistrations().then((regs) => {
|
||||
regs.forEach((r) => r.unregister());
|
||||
}).catch(() => {});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
+9
-24
@@ -1,33 +1,18 @@
|
||||
const CACHE_NAME = 'mindsift-pwa-v1';
|
||||
const ASSETS = ['/', '/index.html', '/manifest.json'];
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil(
|
||||
caches.open(CACHE_NAME).then((cache) => cache.addAll(ASSETS))
|
||||
);
|
||||
// Network-first / cache-clearing service worker to ensure fresh builds across all browsers
|
||||
self.addEventListener('install', () => {
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
event.waitUntil(
|
||||
caches.keys().then((keys) =>
|
||||
Promise.all(keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k)))
|
||||
)
|
||||
caches
|
||||
.keys()
|
||||
.then((keys) => Promise.all(keys.map((k) => caches.delete(k))))
|
||||
.then(() => self.clients.claim())
|
||||
);
|
||||
self.clients.claim();
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
if (event.request.method !== 'GET' || event.request.url.includes('/api/')) {
|
||||
return;
|
||||
}
|
||||
event.respondWith(
|
||||
fetch(event.request)
|
||||
.then((res) => {
|
||||
const clone = res.clone();
|
||||
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone));
|
||||
return res;
|
||||
})
|
||||
.catch(() => caches.match(event.request).then((cached) => cached || caches.match('/')))
|
||||
);
|
||||
self.addEventListener('fetch', () => {
|
||||
// Always use native browser network fetch so API calls and fresh Vite bundles are never intercepted by stale caches
|
||||
return;
|
||||
});
|
||||
@@ -148,40 +148,46 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
|
||||
const effectiveTarget = overrideTarget || target;
|
||||
const effectiveListId =
|
||||
overrideListId || targetListId || (lists.length > 0 ? lists[0].id : '');
|
||||
const capturedPriority = priority;
|
||||
const capturedDueDate = dueDate;
|
||||
const capturedSource = isListening ? 'voice' : 'manual';
|
||||
|
||||
// Optimistically clear input immediately so the UI feels instant (<10ms) in all browsers
|
||||
setContent('');
|
||||
setPriority('normal');
|
||||
setDueDate('');
|
||||
setTarget('inbox');
|
||||
setShowOptions(false);
|
||||
setIsSubmitting(true);
|
||||
triggerHaptic(15);
|
||||
|
||||
const savedMsg =
|
||||
effectiveTarget === 'task'
|
||||
? 'Als Aufgabe!'
|
||||
: effectiveTarget === 'list_item'
|
||||
? 'Auf Liste!'
|
||||
: effectiveTarget === 'document'
|
||||
? 'Als Notiz!'
|
||||
: 'Im Dump!';
|
||||
setJustSavedLabel(savedMsg);
|
||||
setTimeout(() => setJustSavedLabel(null), 1600);
|
||||
inputRef.current?.focus();
|
||||
|
||||
try {
|
||||
const created = await api.captureThought(
|
||||
trimmed,
|
||||
priority,
|
||||
isListening ? 'voice' : 'manual',
|
||||
dueDate,
|
||||
capturedPriority,
|
||||
capturedSource,
|
||||
capturedDueDate,
|
||||
{
|
||||
target: effectiveTarget,
|
||||
targetListId: effectiveTarget === 'list_item' ? effectiveListId : '',
|
||||
}
|
||||
);
|
||||
setContent('');
|
||||
setPriority('normal');
|
||||
setDueDate('');
|
||||
setTarget('inbox');
|
||||
setShowOptions(false);
|
||||
|
||||
const savedMsg =
|
||||
effectiveTarget === 'task'
|
||||
? 'Als Aufgabe!'
|
||||
: effectiveTarget === 'list_item'
|
||||
? 'Auf Liste!'
|
||||
: effectiveTarget === 'document'
|
||||
? 'Als Notiz!'
|
||||
: 'Im Dump!';
|
||||
setJustSavedLabel(savedMsg);
|
||||
setTimeout(() => setJustSavedLabel(null), 1600);
|
||||
|
||||
onCaptured(created, effectiveTarget);
|
||||
inputRef.current?.focus();
|
||||
} catch {
|
||||
// Restore text if capture unexpectedly failed completely
|
||||
setContent(trimmed);
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
@@ -221,6 +227,12 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
|
||||
type="text"
|
||||
value={content}
|
||||
onChange={(e) => setContent(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
executeCapture();
|
||||
}
|
||||
}}
|
||||
placeholder={
|
||||
isListening
|
||||
? 'Ich höre zu…'
|
||||
|
||||
+16
-4
@@ -40,6 +40,7 @@ async function request<T>(path: string, options: RequestInit = {}, isRetry = fal
|
||||
const token = getToken();
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
...(options.headers as Record<string, string>),
|
||||
};
|
||||
|
||||
@@ -47,16 +48,27 @@ async function request<T>(path: string, options: RequestInit = {}, isRetry = fal
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
const res = await fetch(path, {
|
||||
...options,
|
||||
headers,
|
||||
});
|
||||
const controller = new AbortController();
|
||||
const timeoutId = window.setTimeout(() => controller.abort(), 8000);
|
||||
|
||||
let res: Response;
|
||||
try {
|
||||
res = await fetch(path, {
|
||||
...options,
|
||||
headers,
|
||||
cache: 'no-store',
|
||||
signal: controller.signal,
|
||||
});
|
||||
} finally {
|
||||
window.clearTimeout(timeoutId);
|
||||
}
|
||||
|
||||
if (res.status === 401 && !isRetry && !path.includes('/auth/login') && !path.includes('/auth/quickstart')) {
|
||||
try {
|
||||
const qsRes = await fetch('/api/v1/auth/quickstart', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
cache: 'no-store',
|
||||
});
|
||||
if (qsRes.ok) {
|
||||
const qsData = await qsRes.json();
|
||||
|
||||
Reference in new issue
Block a user