@firstlovecenter/ai-chat 0.9.1 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ui/index.cjs CHANGED
@@ -723,6 +723,11 @@ function AiChat({
723
723
  cancelled = true;
724
724
  };
725
725
  }, []);
726
+ React.useEffect(() => {
727
+ if (initialSessionId != null && activeSessionId !== initialSessionId) {
728
+ setActiveSessionId(initialSessionId);
729
+ }
730
+ }, [initialSessionId]);
726
731
  React.useEffect(() => {
727
732
  if (initialSessionId == null) {
728
733
  setAnswers([]);
@@ -735,13 +740,18 @@ function AiChat({
735
740
  const res = await fetch(`/api/chat/sessions/${id}`, { cache: "no-store" });
736
741
  if (cancelled) return;
737
742
  if (!res.ok) {
743
+ console.warn(
744
+ "[AiChat] hydration: GET /api/chat/sessions failed",
745
+ { id, status: res.status }
746
+ );
738
747
  setAnswers([]);
739
748
  return;
740
749
  }
741
750
  const data = await res.json();
742
751
  if (cancelled) return;
743
752
  setAnswers(messagesToAnswers(data.messages ?? []));
744
- } catch {
753
+ } catch (err) {
754
+ console.error("[AiChat] hydration threw \u2014 setting empty answers", err);
745
755
  if (!cancelled) setAnswers([]);
746
756
  } finally {
747
757
  if (!cancelled) setLoadingSession(false);
@@ -874,7 +884,9 @@ function AiChat({
874
884
  const data = await create.json();
875
885
  sessionId = data.session.id;
876
886
  setActiveSessionId(sessionId);
877
- syncUrl(sessionId);
887
+ if (typeof window !== "undefined") {
888
+ window.history.replaceState(null, "", `${basePath}/${sessionId}`);
889
+ }
878
890
  setSessions((prev) => [
879
891
  { id: data.session.id, title: data.session.title, updatedAt: null },
880
892
  ...prev
@@ -936,6 +948,17 @@ function AiChat({
936
948
  const events = buffer.split("\n\n");
937
949
  buffer = events.pop() ?? "";
938
950
  for (const raw of events) {
951
+ const meta = parseMetaChatSessionId(raw);
952
+ if (meta != null) {
953
+ setActiveSessionId((prev) => prev ?? meta);
954
+ if (typeof window !== "undefined" && !window.location.pathname.endsWith(`/${meta}`)) {
955
+ window.history.replaceState(
956
+ null,
957
+ "",
958
+ `${basePath}/${meta}`
959
+ );
960
+ }
961
+ }
939
962
  handleEvent(raw, setAnswers);
940
963
  }
941
964
  }
@@ -1394,6 +1417,22 @@ function UserChip({ text }) {
1394
1417
  )
1395
1418
  ] });
1396
1419
  }
1420
+ function parseMetaChatSessionId(raw) {
1421
+ const lines = raw.split("\n");
1422
+ let event = "";
1423
+ let dataStr = "";
1424
+ for (const line of lines) {
1425
+ if (line.startsWith("event: ")) event = line.slice(7).trim();
1426
+ else if (line.startsWith("data: ")) dataStr += line.slice(6);
1427
+ }
1428
+ if (event !== "meta") return null;
1429
+ try {
1430
+ const parsed = JSON.parse(dataStr || "{}");
1431
+ return typeof parsed.chatSessionId === "string" && parsed.chatSessionId.length > 0 ? parsed.chatSessionId : null;
1432
+ } catch {
1433
+ return null;
1434
+ }
1435
+ }
1397
1436
  function handleEvent(raw, setAnswers) {
1398
1437
  const lines = raw.split("\n");
1399
1438
  let event = "";
@@ -1454,6 +1493,15 @@ function updateLast(prev, updater) {
1454
1493
  next[next.length - 1] = updater(next[next.length - 1]);
1455
1494
  return next;
1456
1495
  }
1496
+ function coerceJsonField(v) {
1497
+ if (v == null) return null;
1498
+ if (typeof v !== "string") return v;
1499
+ try {
1500
+ return JSON.parse(v);
1501
+ } catch {
1502
+ return null;
1503
+ }
1504
+ }
1457
1505
  function messagesToAnswers(messages) {
1458
1506
  const out = [];
1459
1507
  let pendingUser = null;
@@ -1464,19 +1512,24 @@ function messagesToAnswers(messages) {
1464
1512
  const question = pendingUser ?? "";
1465
1513
  pendingUser = null;
1466
1514
  const blocks = [];
1467
- const stored = m.blocks ?? [];
1468
- stored.forEach((b, i) => {
1469
- const sanitised = sanitiseBlock({ ...b});
1470
- if (sanitised.kind === "paragraph_brief") {
1471
- sanitised.prose = m.prose?.[String(i)] ?? "";
1472
- }
1473
- blocks[i] = sanitised;
1474
- });
1515
+ const storedBlocks = coerceJsonField(m.blocks) ?? [];
1516
+ const storedProse = coerceJsonField(m.prose) ?? {};
1517
+ const storedError = coerceJsonField(m.errorJson);
1518
+ if (Array.isArray(storedBlocks)) {
1519
+ storedBlocks.forEach((b, i) => {
1520
+ const sanitised = sanitiseBlock({
1521
+ ...b});
1522
+ if (sanitised.kind === "paragraph_brief") {
1523
+ sanitised.prose = storedProse[String(i)] ?? "";
1524
+ }
1525
+ blocks[i] = sanitised;
1526
+ });
1527
+ }
1475
1528
  out.push({
1476
1529
  question,
1477
1530
  blocks,
1478
1531
  done: true,
1479
- error: m.errorJson ?? void 0
1532
+ error: storedError ?? void 0
1480
1533
  });
1481
1534
  }
1482
1535
  }
@@ -1646,6 +1699,20 @@ function VercelChat({
1646
1699
  cancelled = true;
1647
1700
  };
1648
1701
  }, [initialSessionId, setMessages]);
1702
+ React.useEffect(() => {
1703
+ if (!Array.isArray(data)) return;
1704
+ for (const raw of data) {
1705
+ const part = asDataPart(raw);
1706
+ if (!part || part.type !== "meta") continue;
1707
+ const id = part.value.chatSessionId;
1708
+ if (!id) continue;
1709
+ setActiveSessionId((prev) => prev ?? id);
1710
+ if (typeof window !== "undefined" && !window.location.pathname.endsWith(`/${id}`)) {
1711
+ window.history.replaceState(null, "", `${basePath}/${id}`);
1712
+ }
1713
+ break;
1714
+ }
1715
+ }, [data, basePath]);
1649
1716
  const answers = React.useMemo(() => {
1650
1717
  const liveBlocks = [];
1651
1718
  const liveErrors = [];
@@ -1868,7 +1935,13 @@ function VercelChat({
1868
1935
  const json = await create.json();
1869
1936
  activeSessionIdRef.current = json.session.id;
1870
1937
  setActiveSessionId(json.session.id);
1871
- syncUrl(json.session.id);
1938
+ if (typeof window !== "undefined") {
1939
+ window.history.replaceState(
1940
+ null,
1941
+ "",
1942
+ `${basePath}/${json.session.id}`
1943
+ );
1944
+ }
1872
1945
  setSessions((prev) => [
1873
1946
  { id: json.session.id, title: json.session.title, updatedAt: null },
1874
1947
  ...prev
@@ -2352,6 +2425,15 @@ function UserChip2({ text }) {
2352
2425
  )
2353
2426
  ] });
2354
2427
  }
2428
+ function coerceJsonField2(v) {
2429
+ if (v == null) return null;
2430
+ if (typeof v !== "string") return v;
2431
+ try {
2432
+ return JSON.parse(v);
2433
+ } catch {
2434
+ return null;
2435
+ }
2436
+ }
2355
2437
  function storedToUseChat(stored) {
2356
2438
  const uiMessages = [];
2357
2439
  const blocksMap = {};
@@ -2367,15 +2449,20 @@ function storedToUseChat(stored) {
2367
2449
  if (m.role === "assistant") {
2368
2450
  const id = `assistant-${m.id}`;
2369
2451
  const blocks = [];
2370
- const stored2 = m.blocks ?? [];
2371
- stored2.forEach((b, i) => {
2372
- const sanitised = sanitiseBlock({ ...b});
2373
- if (sanitised.kind === "paragraph_brief") {
2374
- sanitised.prose = m.prose?.[String(i)] ?? "";
2375
- }
2376
- blocks[i] = sanitised;
2377
- });
2378
- const joinedProse = Object.values(m.prose ?? {}).filter(Boolean).join("\n\n");
2452
+ const storedBlocks = coerceJsonField2(m.blocks) ?? [];
2453
+ const storedProse = coerceJsonField2(m.prose) ?? {};
2454
+ const storedError = coerceJsonField2(m.errorJson);
2455
+ if (Array.isArray(storedBlocks)) {
2456
+ storedBlocks.forEach((b, i) => {
2457
+ const sanitised = sanitiseBlock({
2458
+ ...b});
2459
+ if (sanitised.kind === "paragraph_brief") {
2460
+ sanitised.prose = storedProse[String(i)] ?? "";
2461
+ }
2462
+ blocks[i] = sanitised;
2463
+ });
2464
+ }
2465
+ const joinedProse = Object.values(storedProse).filter(Boolean).join("\n\n");
2379
2466
  uiMessages.push({
2380
2467
  id,
2381
2468
  role: "assistant",
@@ -2383,7 +2470,7 @@ function storedToUseChat(stored) {
2383
2470
  });
2384
2471
  blocksMap[id] = blocks;
2385
2472
  if (joinedProse) proseMap[id] = joinedProse;
2386
- if (m.errorJson) errorsMap[id] = m.errorJson;
2473
+ if (storedError) errorsMap[id] = storedError;
2387
2474
  }
2388
2475
  }
2389
2476
  return { uiMessages, blocksMap, proseMap, errorsMap };