diff --git a/public/proto/home-v5.html b/public/proto/home-v5.html index 2d6037bb..62ef9e0f 100644 --- a/public/proto/home-v5.html +++ b/public/proto/home-v5.html @@ -5421,6 +5421,45 @@

Keyboard shortcuts

return; } + // ─── Cold-load send guard (PR B) ─────────────────────────────────── + // Until the Convex-routing override installs below (AFTER the browser client + // lazy-loads AND joinEvent resolves), window.sendComposerMessage is still the + // prototype-only handler — it clears the composer and renders locally but + // NEVER persists to Convex. A public send fired in this cold-load window would + // be silently lost (the user thinks it sent). Install a queueing shim now: + // public sends are buffered (not lost), the composer clears, and a "connecting" + // hint shows. The real override drains the queue the moment the room is live; + // if init fails, _sn_failPendingSends restores the draft instead of dropping it. + window._sn_pendingSends = []; + const _preInitSend = window.sendComposerMessage; + window.sendComposerMessage = function() { + const input = document.getElementById('ci'); + if (!input) return; + const intent = window.parseComposerIntent && window.parseComposerIntent(input.value); + if (!intent) { input.focus(); return; } + // Private notes stay 100% prototype-side and never touch Convex — pass through. + if (intent.visibility === 'private') { return _preInitSend.call(this); } + window._sn_pendingSends.push(input.value); + input.value = ''; + if ('ontouchstart' in window || window.innerWidth <= 720) input.blur(); + if (typeof toast === 'function') { + toast('Connecting to live room…', 'Your message will send the moment the room is live.'); + } + }; + window.send = window.sendComposerMessage; + window._sn_failPendingSends = function() { + if (!window._sn_pendingSends || !window._sn_pendingSends.length) return; + const input = document.getElementById('ci'); + const lastDraft = window._sn_pendingSends[window._sn_pendingSends.length - 1]; + window._sn_pendingSends = []; + // Restore the most recent un-sent draft so the user can retry once the room + // recovers — never silently drop what they typed. + if (input && !input.value) input.value = lastDraft; + if (typeof toast === 'function') { + toast('Live room unavailable', 'Your message was not sent — your draft is restored. Retry once the room loads.'); + } + }; + // ─── Lazy-load Convex browser client ─────────────────────────────── let ConvexClient; try { @@ -5430,6 +5469,7 @@

Keyboard shortcuts

} catch (e) { console.warn('[scratchnode] Convex client load failed, live room unavailable:', e.message); showLiveRoomError('Could not load the realtime client. Retry'); + window._sn_failPendingSends && window._sn_failPendingSends(); return; } @@ -5452,6 +5492,7 @@

Keyboard shortcuts

showLiveRoomError(notFound ? 'No room matches /e/' + (slug.replace(/[<>&"]/g, '') || '?') + '. Back to landing or check your room code.' : 'Could not connect to the live room. Retry'); + window._sn_failPendingSends && window._sn_failPendingSends(); return; } const eventId = joined.eventId; @@ -5681,6 +5722,20 @@

Keyboard shortcuts

// Make sure both global aliases stay in sync (existing onclick handlers). window.send = window.sendComposerMessage; + // Drain any public sends queued during the cold-load init window (PR B). The + // real override reads #ci, so replay each buffered draft through it in order — + // each goes through the full Convex sendMessage → askAgent path and clears. + if (window._sn_pendingSends && window._sn_pendingSends.length) { + const _queued = window._sn_pendingSends.splice(0); + const _ci = document.getElementById('ci'); + if (_ci) { + for (let _i = 0; _i < _queued.length; _i += 1) { + _ci.value = _queued[_i]; + window.sendComposerMessage(); + } + } + } + window.snSuggestFaq = function(answerId) { client.mutation('events:suggestAnswerForFaq', { eventId, answerId, sessionId }) .then(() => toast('Suggested for FAQ', 'The host can promote this into the public wiki.'))