fix: finish new-session opening-message handoff
This commit is contained in:
@@ -1,41 +1,59 @@
|
||||
/**
|
||||
* The opening message rides beside the navigation, never in the URL.
|
||||
*
|
||||
* Home and the new-session draft used to push `/chat/<id>?prompt=<text>`.
|
||||
* Node's default max HTTP header size is 16KB. A long paste (a syllabus)
|
||||
* makes that GET return 431, and Electron commits an empty document: the
|
||||
* window stays the native background and looks frozen. The chat record
|
||||
* already exists, with an empty transcript, because POST /api/chats
|
||||
* succeeded first.
|
||||
*
|
||||
* sessionStorage holds the trimmed text under `lh.openingPrompt.<id>`.
|
||||
* The push target stays `/chat/<id>`. The chat page still honors a
|
||||
* `?prompt=` search param for an old link; when that param is absent it
|
||||
* reads this stash and sends it once. The stash survives until that send
|
||||
* resolves, so a reload before the POST lands can retry. Absent storage
|
||||
* (node tests, a thrown access) is a no-op — the short path still returns.
|
||||
* Same-tab handover of a new session's full opening text. Never put the
|
||||
* message in the navigation URL: long query payloads can be rejected before
|
||||
* the chat page loads. Storage is required for automatic delivery, not an
|
||||
* optional best-effort side effect of navigating away from the source draft.
|
||||
*/
|
||||
export const OPENING_PROMPT_FAILURE = "Couldn’t open the session. Your message is still here. Try sending again.";
|
||||
|
||||
export interface OpeningPrompt {
|
||||
text: string;
|
||||
/** Written BEFORE sending. A later mount restores a draft, never reposts. */
|
||||
attempted: boolean;
|
||||
}
|
||||
|
||||
const keyFor = (id: string) => `lh.openingPrompt.${id}`;
|
||||
|
||||
function store(): Storage | null {
|
||||
export function stashOpeningPrompt(id: string, text: string, attempted = false): boolean {
|
||||
try {
|
||||
if (typeof sessionStorage === "undefined" || sessionStorage == null) return null;
|
||||
return sessionStorage;
|
||||
const value = JSON.stringify({ text, attempted } satisfies OpeningPrompt);
|
||||
// Catch both the storage getter and its methods (quota/security errors).
|
||||
const storage = globalThis.sessionStorage;
|
||||
storage.setItem(keyFor(id), value);
|
||||
return storage.getItem(keyFor(id)) === value;
|
||||
} catch {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function stashOpeningPrompt(id: string, text: string): void {
|
||||
store()?.setItem(keyFor(id), text);
|
||||
export function readOpeningPromptEntry(id: string): OpeningPrompt | undefined {
|
||||
try {
|
||||
const value = globalThis.sessionStorage.getItem(keyFor(id));
|
||||
if (!value) return undefined;
|
||||
try {
|
||||
const entry: unknown = JSON.parse(value);
|
||||
if (entry && typeof entry === "object" && "text" in entry && typeof entry.text === "string" &&
|
||||
entry.text.length > 0 && "attempted" in entry && typeof entry.attempted === "boolean") {
|
||||
return { text: entry.text, attempted: entry.attempted };
|
||||
}
|
||||
} catch { /* Old raw-text stashes have no proof that sending never began. */ }
|
||||
return { text: value, attempted: true };
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function readOpeningPrompt(id: string): string | undefined {
|
||||
const value = store()?.getItem(keyFor(id));
|
||||
return value && value.length > 0 ? value : undefined;
|
||||
return readOpeningPromptEntry(id)?.text;
|
||||
}
|
||||
|
||||
export function clearOpeningPrompt(id: string): void {
|
||||
store()?.removeItem(keyFor(id));
|
||||
export function clearOpeningPrompt(id: string): boolean {
|
||||
try {
|
||||
globalThis.sessionStorage.removeItem(keyFor(id));
|
||||
return true;
|
||||
} catch {
|
||||
// Canonical conversation/acknowledgment remains the truth. A later
|
||||
// mount with real conversation can try cleanup again; never crash it.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user