@flamingo-stack/openframe-frontend-core 0.0.489 → 0.0.490-1506.3944.1
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/chat-protocol/decode.d.ts +58 -0
- package/dist/chat-protocol/decode.d.ts.map +1 -0
- package/dist/chat-protocol/encode.d.ts +44 -0
- package/dist/chat-protocol/encode.d.ts.map +1 -0
- package/dist/chat-protocol/env-flag.d.ts +35 -0
- package/dist/chat-protocol/env-flag.d.ts.map +1 -0
- package/dist/chat-protocol/events.d.ts +196 -0
- package/dist/chat-protocol/events.d.ts.map +1 -0
- package/dist/chat-protocol/frames.d.ts +213 -0
- package/dist/chat-protocol/frames.d.ts.map +1 -0
- package/dist/chat-protocol/index.cjs +494 -0
- package/dist/chat-protocol/index.cjs.map +1 -0
- package/dist/chat-protocol/index.d.ts +18 -0
- package/dist/chat-protocol/index.d.ts.map +1 -0
- package/dist/chat-protocol/index.js +478 -0
- package/dist/chat-protocol/index.js.map +1 -0
- package/dist/chat-protocol/ip-normalize.d.ts +44 -0
- package/dist/chat-protocol/ip-normalize.d.ts.map +1 -0
- package/dist/chat-protocol/nats-decoder.d.ts +26 -0
- package/dist/chat-protocol/nats-decoder.d.ts.map +1 -0
- package/dist/{chunk-K7MNWYYI.js → chunk-4NWARV5I.js} +2 -2
- package/dist/{chunk-2RNJYJWO.cjs → chunk-5CJR2GZ4.cjs} +31 -31
- package/dist/{chunk-2RNJYJWO.cjs.map → chunk-5CJR2GZ4.cjs.map} +1 -1
- package/dist/{chunk-H3YRJ3LZ.cjs → chunk-5EYRXSY5.cjs} +9 -9
- package/dist/{chunk-H3YRJ3LZ.cjs.map → chunk-5EYRXSY5.cjs.map} +1 -1
- package/dist/{chunk-IN4IO7BL.cjs → chunk-5LMGFI4J.cjs} +6930 -4755
- package/dist/chunk-5LMGFI4J.cjs.map +1 -0
- package/dist/{chunk-YMJZOANX.js → chunk-BE6DK7QY.js} +12228 -10053
- package/dist/chunk-BE6DK7QY.js.map +1 -0
- package/dist/{chunk-TWGYBXYV.js → chunk-CORIBKHG.js} +2 -2
- package/dist/{chunk-RO7Q56ZK.cjs → chunk-CSYSYJCF.cjs} +37 -37
- package/dist/{chunk-RO7Q56ZK.cjs.map → chunk-CSYSYJCF.cjs.map} +1 -1
- package/dist/{chunk-Z7Y63IFU.cjs → chunk-DSDZ5T4P.cjs} +5 -5
- package/dist/{chunk-Z7Y63IFU.cjs.map → chunk-DSDZ5T4P.cjs.map} +1 -1
- package/dist/{chunk-EU6QNO4S.js → chunk-GTWO5NAY.js} +2 -2
- package/dist/{chunk-BGWDDB7Y.js → chunk-HSACATCD.js} +2 -2
- package/dist/{chunk-3OIB763B.cjs → chunk-NWX7MMF5.cjs} +15 -15
- package/dist/{chunk-3OIB763B.cjs.map → chunk-NWX7MMF5.cjs.map} +1 -1
- package/dist/{chunk-J7H32E3R.cjs → chunk-P4WTZU6L.cjs} +11 -11
- package/dist/{chunk-J7H32E3R.cjs.map → chunk-P4WTZU6L.cjs.map} +1 -1
- package/dist/{chunk-VLOE7MI2.cjs → chunk-Q6E7VJ4W.cjs} +28 -27
- package/dist/chunk-Q6E7VJ4W.cjs.map +1 -0
- package/dist/{chunk-ZIAS5NNL.cjs → chunk-QSCHCZL3.cjs} +7 -7
- package/dist/{chunk-ZIAS5NNL.cjs.map → chunk-QSCHCZL3.cjs.map} +1 -1
- package/dist/{chunk-VL4LUO32.js → chunk-RQLBHKXN.js} +2 -2
- package/dist/{chunk-5YMY4BAW.cjs → chunk-S2NHJDKQ.cjs} +62 -62
- package/dist/{chunk-5YMY4BAW.cjs.map → chunk-S2NHJDKQ.cjs.map} +1 -1
- package/dist/{chunk-N4MTNTSX.js → chunk-T2EGSZFN.js} +6 -5
- package/dist/chunk-T2EGSZFN.js.map +1 -0
- package/dist/{chunk-W6ZUOWSB.js → chunk-TKN5667N.js} +10 -10
- package/dist/chunk-TKN5667N.js.map +1 -0
- package/dist/{chunk-B4YR342L.js → chunk-UUYRJPGJ.js} +4 -4
- package/dist/{chunk-FKPXFTZT.js → chunk-VHG6AX5V.js} +2 -2
- package/dist/{chunk-2IHN7NNB.cjs → chunk-VQ523ORK.cjs} +26 -26
- package/dist/{chunk-2IHN7NNB.cjs.map → chunk-VQ523ORK.cjs.map} +1 -1
- package/dist/{chunk-X2YF5TJS.js → chunk-XQ2B74SI.js} +2 -2
- package/dist/{chunk-LLEDO4P7.cjs → chunk-YHOIAA2E.cjs} +60 -60
- package/dist/chunk-YHOIAA2E.cjs.map +1 -0
- package/dist/{chunk-5VSEMWWE.js → chunk-YZ2OIYQ3.js} +4 -4
- package/dist/components/case-studies/index.cjs +8 -8
- package/dist/components/case-studies/index.js +2 -2
- package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
- package/dist/components/chat/chat-message-list.d.ts.map +1 -1
- package/dist/components/chat/hooks/index.d.ts +0 -1
- package/dist/components/chat/hooks/index.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-chat.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +15 -48
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts +10 -57
- package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +10 -2
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.d.ts +1 -0
- package/dist/components/chat/index.d.ts.map +1 -1
- package/dist/components/chat/index.js +21 -13
- package/dist/components/chat/stream/chat-dialog-store.d.ts +184 -0
- package/dist/components/chat/stream/chat-dialog-store.d.ts.map +1 -0
- package/dist/components/chat/stream/chat-stream-reducer.d.ts +367 -0
- package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +1 -0
- package/dist/components/chat/stream/delta-batcher.d.ts +51 -0
- package/dist/components/chat/stream/delta-batcher.d.ts.map +1 -0
- package/dist/components/chat/stream/index.d.ts +17 -0
- package/dist/components/chat/stream/index.d.ts.map +1 -0
- package/dist/components/chat/stream/message-mutations.d.ts +77 -0
- package/dist/components/chat/stream/message-mutations.d.ts.map +1 -0
- package/dist/components/chat/stream/use-chat-stream-reducer.d.ts +22 -0
- package/dist/components/chat/stream/use-chat-stream-reducer.d.ts.map +1 -0
- package/dist/components/chat/types/api.types.d.ts +1 -81
- package/dist/components/chat/types/api.types.d.ts.map +1 -1
- package/dist/components/chat/types/processing.types.d.ts +2 -90
- package/dist/components/chat/types/processing.types.d.ts.map +1 -1
- package/dist/components/chat/utils/extract-incomplete-message-state.d.ts +34 -6
- package/dist/components/chat/utils/extract-incomplete-message-state.d.ts.map +1 -1
- package/dist/components/chat/utils/index.d.ts +2 -3
- package/dist/components/chat/utils/index.d.ts.map +1 -1
- package/dist/components/chat/utils/process-historical-messages.d.ts +59 -11
- package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +3 -3
- package/dist/components/contact/index.js +2 -2
- package/dist/components/docs/index.cjs +5 -5
- package/dist/components/docs/index.js +4 -4
- package/dist/components/embeds/index.cjs +3 -3
- package/dist/components/embeds/index.js +2 -2
- package/dist/components/faq/index.cjs +3 -3
- package/dist/components/faq/index.js +2 -2
- package/dist/components/features/index.cjs +2 -2
- package/dist/components/features/index.js +1 -1
- package/dist/components/help-center-pages/index.cjs +20 -20
- package/dist/components/help-center-pages/index.js +11 -11
- package/dist/components/index.cjs +172 -130
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +63 -21
- package/dist/components/index.js.map +1 -1
- package/dist/components/navigation/index.cjs +2 -2
- package/dist/components/navigation/index.js +1 -1
- package/dist/components/onboarding-guides/index.cjs +5 -5
- package/dist/components/onboarding-guides/index.js +4 -4
- package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
- package/dist/components/related-content/index.cjs +3 -3
- package/dist/components/related-content/index.js +2 -2
- package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
- package/dist/components/tickets/index.cjs +5 -5
- package/dist/components/tickets/index.js +4 -4
- package/dist/components/ui/index.cjs +44 -2
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.d.ts +1 -2
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +55 -13
- package/dist/components/ui/markdown/base-components.d.ts +51 -0
- package/dist/components/ui/markdown/base-components.d.ts.map +1 -0
- package/dist/components/ui/markdown/engine.d.ts +99 -0
- package/dist/components/ui/markdown/engine.d.ts.map +1 -0
- package/dist/components/ui/markdown/heading-ids.d.ts +65 -0
- package/dist/components/ui/markdown/heading-ids.d.ts.map +1 -0
- package/dist/components/ui/markdown/index.d.ts +18 -0
- package/dist/components/ui/markdown/index.d.ts.map +1 -0
- package/dist/components/ui/markdown/mermaid-diagram.d.ts +79 -0
- package/dist/components/ui/markdown/mermaid-diagram.d.ts.map +1 -0
- package/dist/components/ui/markdown/rich/embed-overrides.d.ts +14 -0
- package/dist/components/ui/markdown/rich/embed-overrides.d.ts.map +1 -0
- package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts +40 -0
- package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts.map +1 -0
- package/dist/components/ui/markdown/rich/shortcodes.d.ts +8 -0
- package/dist/components/ui/markdown/rich/shortcodes.d.ts.map +1 -0
- package/dist/components/ui/markdown/sanitize.d.ts +153 -0
- package/dist/components/ui/markdown/sanitize.d.ts.map +1 -0
- package/dist/components/ui/markdown/simple-markdown-renderer.d.ts +23 -0
- package/dist/components/ui/markdown/simple-markdown-renderer.d.ts.map +1 -0
- package/dist/components/ui/markdown/streaming.d.ts +78 -0
- package/dist/components/ui/markdown/streaming.d.ts.map +1 -0
- package/dist/components/ui/markdown/text-size.d.ts +34 -0
- package/dist/components/ui/markdown/text-size.d.ts.map +1 -0
- package/dist/index.cjs +60 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +71 -13
- package/dist/utils/index.cjs +169 -40
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +162 -41
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/markdown-fences.d.ts +42 -0
- package/dist/utils/markdown-fences.d.ts.map +1 -0
- package/dist/utils/markdown-heading-id.d.ts +85 -0
- package/dist/utils/markdown-heading-id.d.ts.map +1 -0
- package/dist/utils/markdown-section-extractor.d.ts.map +1 -1
- package/package.json +7 -1
- package/src/chat-protocol/__tests__/__snapshots__/nats-decoder-golden.test.ts.snap +307 -0
- package/src/chat-protocol/__tests__/chat-protocol.test.ts +516 -0
- package/src/chat-protocol/__tests__/env-flag.test.ts +52 -0
- package/src/chat-protocol/__tests__/ip-normalize.test.ts +136 -0
- package/src/chat-protocol/__tests__/nats-decoder-golden.test.ts +228 -0
- package/src/chat-protocol/decode.ts +278 -0
- package/src/chat-protocol/encode.ts +71 -0
- package/src/chat-protocol/env-flag.ts +39 -0
- package/src/chat-protocol/events.ts +232 -0
- package/src/chat-protocol/frames.ts +245 -0
- package/src/chat-protocol/index.ts +21 -0
- package/src/chat-protocol/ip-normalize.ts +146 -0
- package/src/chat-protocol/nats-decoder.ts +252 -0
- package/src/components/chat/__tests__/chat-message-list.test.tsx +293 -5
- package/src/components/chat/__tests__/chat-message-streaming-memo.test.tsx +207 -0
- package/src/components/chat/__tests__/chat-pending-turn.test.tsx +209 -0
- package/src/components/chat/chat-message-enhanced.tsx +111 -17
- package/src/components/chat/chat-message-list.tsx +358 -109
- package/src/components/chat/embeddable-chat.tsx +6 -0
- package/src/components/chat/hooks/.index.md +30 -33
- package/src/components/chat/hooks/.use-nats-chat-adapter.md +36 -55
- package/src/components/chat/hooks/__tests__/__snapshots__/conversation-id-persistence-golden.test.ts.snap +37 -0
- package/src/components/chat/hooks/__tests__/__snapshots__/sse-stream-golden.test.ts.snap +0 -0
- package/src/components/chat/hooks/__tests__/conversation-id-persistence-golden.test.ts +438 -0
- package/src/components/chat/hooks/__tests__/sse-stream-golden.test.ts +318 -0
- package/src/components/chat/hooks/index.ts +0 -1
- package/src/components/chat/hooks/use-chat.ts +8 -0
- package/src/components/chat/hooks/use-nats-chat-adapter.ts +243 -823
- package/src/components/chat/hooks/use-sse-chat-adapter.ts +380 -684
- package/src/components/chat/index.ts +5 -0
- package/src/components/chat/stream/__tests__/__snapshots__/chat-stream-reducer-golden.test.ts.snap +940 -0
- package/src/components/chat/stream/__tests__/chat-dialog-store.test.ts +756 -0
- package/src/components/chat/stream/__tests__/chat-stream-reducer-golden.test.ts +460 -0
- package/src/components/chat/stream/__tests__/chat-stream-reducer.test.ts +894 -0
- package/src/components/chat/stream/__tests__/delta-batcher.test.ts +255 -0
- package/src/components/chat/stream/__tests__/use-chat-stream-reducer.test.ts +98 -0
- package/src/components/chat/stream/chat-dialog-store.ts +536 -0
- package/src/components/chat/stream/chat-stream-reducer.ts +1796 -0
- package/src/components/chat/stream/delta-batcher.ts +159 -0
- package/src/components/chat/stream/index.ts +55 -0
- package/src/components/chat/stream/message-mutations.ts +338 -0
- package/src/components/chat/stream/use-chat-stream-reducer.ts +126 -0
- package/src/components/chat/thinking-display.tsx +1 -1
- package/src/components/chat/types/.api.types.md +39 -49
- package/src/components/chat/types/.processing.types.md +29 -58
- package/src/components/chat/types/api.types.ts +6 -73
- package/src/components/chat/types/processing.types.ts +11 -52
- package/src/components/chat/utils/.index.md +31 -40
- package/src/components/chat/utils/__tests__/__snapshots__/process-historical-messages-golden.test.ts.snap +420 -0
- package/src/components/chat/utils/__tests__/__snapshots__/segment-accumulator-golden.test.ts.snap +605 -0
- package/src/components/chat/utils/__tests__/process-historical-messages-golden.test.ts +317 -0
- package/src/components/chat/utils/__tests__/segment-accumulator-golden.test.ts +270 -0
- package/src/components/chat/utils/extract-incomplete-message-state.ts +63 -5
- package/src/components/chat/utils/index.ts +5 -8
- package/src/components/chat/utils/process-historical-messages.ts +352 -384
- package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +22 -4
- package/src/components/shared/legal-document/legal-document-page.tsx +1 -1
- package/src/components/shared/product-release/release-detail-page.tsx +19 -4
- package/src/components/ui/__tests__/__snapshots__/markdown-parity.test.tsx.snap +2420 -0
- package/src/components/ui/__tests__/markdown-parity.test.tsx +2528 -0
- package/src/components/ui/index.ts +1 -2
- package/src/components/ui/markdown/__tests__/mermaid-security.test.ts +115 -0
- package/src/components/ui/markdown/__tests__/mermaid-stale-render.test.tsx +95 -0
- package/src/components/ui/markdown/__tests__/sanitize-invariant.test.ts +309 -0
- package/src/components/ui/markdown/__tests__/streaming.test.tsx +388 -0
- package/src/components/ui/markdown/base-components.tsx +360 -0
- package/src/components/ui/markdown/engine.tsx +315 -0
- package/src/components/ui/markdown/heading-ids.ts +239 -0
- package/src/components/ui/markdown/index.ts +49 -0
- package/src/components/ui/markdown/mermaid-diagram.tsx +291 -0
- package/src/components/ui/markdown/rich/embed-overrides.tsx +199 -0
- package/src/components/ui/markdown/rich/rich-markdown-renderer.tsx +184 -0
- package/src/components/ui/markdown/rich/shortcodes.ts +170 -0
- package/src/components/ui/markdown/sanitize.ts +3499 -0
- package/src/components/ui/markdown/simple-markdown-renderer.tsx +28 -0
- package/src/components/ui/markdown/streaming.ts +362 -0
- package/src/components/ui/markdown/text-size.ts +106 -0
- package/src/components/ui/release-changelog-section.tsx +1 -1
- package/src/components/ui/ticket-info-section.tsx +1 -1
- package/src/utils/index.ts +1 -0
- package/src/utils/markdown-fences.ts +127 -0
- package/src/utils/markdown-heading-id.ts +348 -0
- package/src/utils/markdown-section-extractor.ts +41 -56
- package/dist/chunk-IN4IO7BL.cjs.map +0 -1
- package/dist/chunk-LLEDO4P7.cjs.map +0 -1
- package/dist/chunk-N4MTNTSX.js.map +0 -1
- package/dist/chunk-VLOE7MI2.cjs.map +0 -1
- package/dist/chunk-W6ZUOWSB.js.map +0 -1
- package/dist/chunk-YMJZOANX.js.map +0 -1
- package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts +0 -6
- package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts.map +0 -1
- package/dist/components/chat/utils/chunk-parser.d.ts +0 -25
- package/dist/components/chat/utils/chunk-parser.d.ts.map +0 -1
- package/dist/components/ui/rich-markdown-renderer.d.ts +0 -34
- package/dist/components/ui/rich-markdown-renderer.d.ts.map +0 -1
- package/dist/components/ui/simple-markdown-renderer.d.ts +0 -73
- package/dist/components/ui/simple-markdown-renderer.d.ts.map +0 -1
- package/src/components/chat/hooks/.use-realtime-chunk-processor.md +0 -77
- package/src/components/chat/hooks/use-realtime-chunk-processor.ts +0 -479
- package/src/components/chat/utils/.chunk-parser.md +0 -62
- package/src/components/chat/utils/chunk-parser.ts +0 -256
- package/src/components/ui/.simple-markdown-renderer.md +0 -52
- package/src/components/ui/rich-markdown-renderer.tsx +0 -1223
- package/src/components/ui/simple-markdown-renderer.tsx +0 -964
- /package/dist/{chunk-K7MNWYYI.js.map → chunk-4NWARV5I.js.map} +0 -0
- /package/dist/{chunk-TWGYBXYV.js.map → chunk-CORIBKHG.js.map} +0 -0
- /package/dist/{chunk-EU6QNO4S.js.map → chunk-GTWO5NAY.js.map} +0 -0
- /package/dist/{chunk-BGWDDB7Y.js.map → chunk-HSACATCD.js.map} +0 -0
- /package/dist/{chunk-VL4LUO32.js.map → chunk-RQLBHKXN.js.map} +0 -0
- /package/dist/{chunk-B4YR342L.js.map → chunk-UUYRJPGJ.js.map} +0 -0
- /package/dist/{chunk-FKPXFTZT.js.map → chunk-VHG6AX5V.js.map} +0 -0
- /package/dist/{chunk-X2YF5TJS.js.map → chunk-XQ2B74SI.js.map} +0 -0
- /package/dist/{chunk-5VSEMWWE.js.map → chunk-YZ2OIYQ3.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/chat-protocol/frames.ts","../../src/chat-protocol/events.ts","../../src/chat-protocol/encode.ts","../../src/chat-protocol/decode.ts","../../src/components/chat/types/message.types.ts","../../src/chat-protocol/nats-decoder.ts","../../src/chat-protocol/ip-normalize.ts","../../src/chat-protocol/env-flag.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * SSE wire-protocol frame shapes — the byte-level contract between the\n * hub's chat stream emitter (`multi-platform-hub/lib/utils/claude-util.ts`)\n * and the lib's SSE decoder (`./decode.ts`).\n *\n * Wire format (custom byte framing, NOT standard SSE `data:` lines):\n *\n * [JSON frame]\\0 [JSON frame]\\0 … \\x1E <raw UTF-8 answer deltas> \\x1F [JSON usage trailer]\n *\n * 1. LEADING frames — each a JSON object terminated by `\\0`\n * (FRAME_TERMINATOR). Status, metadata, routing, live thinking\n * deltas, usage:start, tool approval frames.\n * 2. ONE `\\x1E` byte (END_OF_LEADING) — flips the stream into raw\n * UTF-8 answer-text mode.\n * 3. `\\x1F` (TRAILER_SENTINEL) + one JSON usage frame running to\n * stream end (no terminator).\n *\n * Server-safe: no React, no browser APIs beyond TextEncoder/TextDecoder.\n */\n\n// =============================================================================\n// Sentinel constants\n// =============================================================================\n\n/** Terminates every leading JSON frame. */\nexport const FRAME_TERMINATOR = '\\0'\n/** Record Separator — end of leading frames, start of raw answer text. */\nexport const END_OF_LEADING = '\\x1E'\n/** Unit Separator — start of the trailing usage JSON frame. */\nexport const TRAILER_SENTINEL = '\\x1F'\n\n// =============================================================================\n// Routing types (moved verbatim from the hub's `lib/chat/wire-frames.ts`;\n// `RouteComplexity` is lib-local so the lib never imports hub code)\n// =============================================================================\n\n/** Server-side routing complexity tiers. Mirror of the hub's\n * `lib/constants/ai-models.ts` union — kept as a lib-local literal type\n * so the wire SSOT has zero hub imports. The DECODER accepts any string\n * (older/newer servers may ship values outside this union). */\nexport type RouteComplexity = 'trivial' | 'default' | 'complex' | 'deep'\n\n/**\n * Routing decision frame. Emitted once per turn as a LEADING frame\n * (between metadata and the `\\x1E` end-of-leading-frames sentinel) when\n * the server's `decideRoute()` produces a `Route`.\n *\n * Field names use the `routed*` prefix on PURPOSE — the client's\n * catch-all leading-frame branch inspects `meta.model` / `meta.modelLabel`.\n * A bare `model` field on this frame would OVERWRITE the metadata frame's\n * modelLabel and break the <ModelDisplay> badge. The `routed` prefix\n * sidesteps that collision.\n *\n * Older clients that don't recognize `kind: 'routing'` silently drop\n * the frame (the catch-all only matches frames carrying known fields\n * like `sources` / `refs` / `modelLabel`).\n */\nexport interface RoutingFrame {\n kind: 'routing'\n routedComplexity: RouteComplexity\n routedModel: string\n routedThinkingBudget: number\n}\n\n/**\n * Optional field on the trailing usage frame's `breakdown`. Surfaces\n * per-route attribution to the admin test console so an operator can\n * see \"this turn ran on Haiku/trivial/$0.0005\" without re-parsing the\n * stream. Additive: clients that ignore unknown keys keep working.\n */\nexport interface RoutedAnswerBreakdown {\n model: string\n complexity: RouteComplexity\n thinkingBudget: number\n}\n\n// =============================================================================\n// Leading frames\n// =============================================================================\n\n/** First frame on every stream — lets the shell render \"Thinking…\"\n * within ~200ms, before any upstream byte arrives. */\nexport interface StatusThinkingFrame {\n status: 'thinking'\n}\n\n/** Per-turn metadata frame. The emitter sends `options.metadata`\n * verbatim; a separate refs-only frame may follow with the same shape.\n * All fields optional — the decoder's catch-all treats ANY frame that\n * didn't match a `kind` discriminant as metadata-ish. */\nexport interface ChatMetadataFrame {\n /** Retrieval sources for the source-chip strip. Host-defined row\n * shape (`ChatSource` on the adapter side) — opaque at wire level. */\n sources?: unknown[]\n /** Per-row refs for inline object cards, keyed `<type>:<id>`. */\n refs?: Record<string, unknown>\n /** Raw model id (e.g. 'claude-sonnet-x'). Presence alone triggers the\n * client's meta merge; the value itself is not stored. */\n model?: string\n modelLabel?: string\n provider?: string\n contextWindowMaxTokens?: number\n /** Per-message viewport-positioning hint ('top' | 'bottom'). */\n scrollAnchor?: string\n /** SERVER-minted conversation trace id (`chat_conversations.id`),\n * echoed on every turn's leading metadata frame. The client never\n * generates ids — the first turn of a session goes out id-less, the\n * server mints one and echoes it here, and the adapter persists the\n * echoed id as its ONLY local state (see\n * `chat-conversation-storage.ts` on the consumer side). */\n conversationId?: string\n}\n\n/** Live adaptive-thinking delta. WIRE IS ALREADY DELTA (Anthropic\n * thinking_delta slices) — decoders must NOT diff or re-accumulate. */\nexport interface ThinkingDeltaFrame {\n kind: 'thinking-delta'\n text: string\n}\n\n/** Usage frame emitted as a LEADING frame right after Anthropic's\n * message_start (stage='start'). */\nexport interface UsageStartFrame {\n kind: 'usage'\n stage: 'start'\n input_tokens: number\n cache_read_input_tokens?: number\n cache_creation_input_tokens?: number\n}\n\n/** Model preamble prose written BEFORE a tool_use block — emitted as a\n * standalone leading frame so it isn't stranded behind the approval\n * card (the `\\x1E` sentinel is suppressed on tool turns). */\nexport interface TextLeadingFrame {\n kind: 'text-leading'\n text: string\n}\n\n/** Tool invocation failed server-side (proposal persist error,\n * validation, ownership denial …). */\nexport interface ToolErrorFrame {\n kind: 'tool_error'\n toolName?: string\n toolUseId?: string\n message: string\n}\n\nexport interface ApprovalRequestField {\n label: string\n value: string\n}\n\n/** The model called a write tool; the server persisted a proposal and\n * ships a card-ready payload. Shape mirrors the hub's `onToolUse`\n * return in `lib/data/doc-chat-utils.ts`. */\nexport interface ApprovalRequestFrame {\n kind: 'approval_request'\n proposalId: string\n toolName: string\n title?: string\n fields?: ApprovalRequestField[]\n preamble?: string | null\n args?: Record<string, unknown>\n expiresAt?: string\n ttlSeconds?: number\n}\n\n/** Server-driven post-approve / post-reject frame (confirm-tool route).\n * Mirror of the hub's `DecisionResolvedFrame` in\n * `lib/data/chat-agent-utils.ts` (tool_name widened to string — the\n * known-write-tool whitelist is host-side knowledge). */\nexport interface DecisionResolvedFrame {\n kind: 'decision_resolved'\n /** The proposal this decision resolved — locates the SOURCE approval\n * card so the shell can flip its status + append the receipt. */\n proposalId: string\n ok: boolean\n action: 'approved' | 'rejected'\n tool_name?: string\n result?: {\n ticket_id?: string\n status?: string | null\n mirror_synced?: boolean\n }\n card?: {\n type: string\n marker: string\n ref: unknown\n }\n /** True when the server WILL pipe an auto-continuation turn after\n * this frame. */\n willAutoContinue: boolean\n /** Pre-rendered receipt copy from the source strategy's\n * `receiptRenderer` — client renders verbatim. */\n receiptText?: string\n}\n\n/** Every leading frame the emitter can produce. */\nexport type SseLeadingFrame =\n | StatusThinkingFrame\n | ChatMetadataFrame\n | RoutingFrame\n | ThinkingDeltaFrame\n | UsageStartFrame\n | TextLeadingFrame\n | ToolErrorFrame\n | ApprovalRequestFrame\n | DecisionResolvedFrame\n\n// =============================================================================\n// Trailing usage frame\n// =============================================================================\n\n/** Card/chip emission counts for admin adoption tooling. */\nexport interface UsageTelemetry {\n cards: number\n chips: number\n sentences: number\n answerLen: number\n}\n\n/** Trailing usage frame — `\\x1F` + JSON, runs to stream end (no\n * terminator). `stage: 'display'` is a legacy alias the decoder treats\n * identically to `'end'`. */\nexport interface SseTrailingUsageFrame {\n kind: 'usage'\n stage: 'end' | 'display'\n input_tokens?: number\n output_tokens?: number\n cache_read_input_tokens?: number\n cache_creation_input_tokens?: number\n hit_rate_pct?: number\n telemetry?: UsageTelemetry\n /** Cross-call usage breakdown (Haiku rewriter / classifier /\n * summarizer + routed-answer attribution). */\n breakdown?: {\n haikuRewriter?: { input: number; output: number }\n haikuClassifier?: { input: number; output: number }\n haikuSummarizer?: { input: number; output: number }\n routedAnswer?: RoutedAnswerBreakdown\n }\n /** Gated deep-debug payload (only present when the request carried\n * the privileged debug secret). */\n debug?: Record<string, unknown>\n}\n","/**\n * Normalized chat stream events — the transport-agnostic event union BOTH\n * decoders (SSE byte framing in `./decode.ts`, NATS chunks in\n * `./nats-decoder.ts`) emit. Phase 3 of the chat unification makes the\n * reducer consume these directly; today the SSE adapter maps them back to\n * legacy `MessageSegment` yields.\n *\n * Server-safe: no React, no browser APIs.\n */\n\n// The wire-frame shapes these events carry through are defined ONCE in\n// `./frames.ts` — reuse them here rather than restating their fields.\nimport type {\n ApprovalRequestField,\n DecisionResolvedFrame,\n UsageTelemetry,\n} from './frames'\n\n/** Optional envelope on every event. `seq` carries the transport's\n * stream sequence (JetStream `streamSeq` on NATS; unused on SSE). */\ninterface ChatStreamEventBase {\n seq?: number\n}\n\n/** Stream entered answer-text mode (SSE: the `\\x1E` sentinel or the\n * JSON-parse-failure fallback; NATS: MESSAGE_START).\n * `implicit` is true ONLY for the SSE fallback path where a\n * non-JSON leading buffer flips straight into text mode — consumers\n * that flush coalesced thinking on turn-start must SKIP the flush for\n * implicit starts (legacy adapter parity: the fallback path never\n * flushed pending thinking before the text). */\nexport interface TurnStartEvent extends ChatStreamEventBase {\n type: 'turn-start'\n implicit?: boolean\n}\n\nexport interface TurnEndEvent extends ChatStreamEventBase {\n type: 'turn-end'\n}\n\n/** Answer text delta. `leading: true` marks SSE `text-leading` frames\n * (model preamble prose emitted BEFORE the tool approval card). */\nexport interface TextDeltaEvent extends ChatStreamEventBase {\n type: 'text-delta'\n text: string\n leading?: boolean\n}\n\n/** Thinking delta — APPEND-ONLY contract: each event carries the next\n * verbatim slice; consumers accumulate. Decoders never diff. */\nexport interface ThinkingDeltaEvent extends ChatStreamEventBase {\n type: 'thinking-delta'\n text: string\n}\n\nexport interface StatusEvent extends ChatStreamEventBase {\n type: 'status'\n phase: 'thinking'\n}\n\n/** NATS tool execution progress (EXECUTING_TOOL / EXECUTED_TOOL). */\nexport interface ToolExecutionEvent extends ChatStreamEventBase {\n type: 'tool-execution'\n data: {\n type: 'EXECUTING_TOOL' | 'EXECUTED_TOOL'\n integratedToolType: string\n toolFunction: string\n toolTitle?: string\n parameters?: Record<string, unknown>\n result?: string\n success?: boolean\n toolExecutionRequestId?: string\n }\n}\n\n/** Single tool call inside a batch approval request (NATS). */\nexport interface ApprovalToolCall {\n toolExecutionRequestId: string\n toolName: string\n toolTitle?: string\n toolExplanation?: string\n toolType?: string\n requiresApproval: boolean\n approvalType?: string | null\n toolCallArguments?: Record<string, unknown> | null\n}\n\n/** A tool call awaits user approval. SSE fills `command`/`fields`\n * (card-ready payload); NATS fills `command`/`explanation` or\n * `toolCalls` (batch form). */\nexport interface ApprovalRequestEvent extends ChatStreamEventBase {\n type: 'approval-request'\n requestId: string\n /** SSE: the write tool's name. NATS: approval tier (USER/ADMIN/…). */\n approvalType?: string\n command?: string\n explanation?: string\n fields?: ApprovalRequestField[]\n toolCalls?: ApprovalToolCall[]\n status?: 'pending'\n}\n\n/** An approval request was resolved (SSE `decision_resolved` frame /\n * NATS APPROVAL_RESULT chunk). */\nexport interface ApprovalResolvedEvent extends ChatStreamEventBase {\n type: 'approval-resolved'\n requestId?: string\n status: 'approved' | 'rejected'\n ok?: boolean\n toolName?: string\n approvalType?: string\n resolvedByName?: string | null\n receiptText?: string\n /** Inline post-approve card: the ref payload + its documentType +\n * the `[card://…]` marker (SSE only). */\n cardRef?: unknown\n cardType?: string\n marker?: string\n result?: DecisionResolvedFrame['result']\n willAutoContinue?: boolean\n}\n\n/** Per-turn metadata. Raw wire values pass through UNVALIDATED — the\n * consumer replicates the legacy truthiness/typeof gates (so a\n * malformed frame degrades identically to the pre-SSOT parser). */\nexport interface ChatMetadataEvent extends ChatStreamEventBase {\n type: 'metadata'\n provider?: string | null\n modelLabel?: string | null\n /** Raw model id (SSE `meta.model`; NATS `modelName`). */\n modelName?: string | null\n contextWindowMaxTokens?: number | null\n sources?: unknown\n refs?: unknown\n scrollAnchor?: unknown\n /** Server-minted conversation id (`ChatMetadataFrame.conversationId`),\n * passed through raw like every other catch-all field — the consumer\n * applies the `typeof === 'string' && truthy` gate. */\n conversationId?: string | null\n routing?: {\n routedComplexity: string\n routedModel?: string\n routedThinkingBudget: number | null\n }\n}\n\n/** SSE usage frames — raw wire keys (snake_case) preserved. */\nexport interface UsageEvent extends ChatStreamEventBase {\n type: 'usage'\n stage: 'start' | 'end'\n input_tokens?: number\n output_tokens?: number\n cache_read_input_tokens?: number\n cache_creation_input_tokens?: number\n hit_rate_pct?: number\n telemetry?: UsageTelemetry\n /** Left OPAQUE on purpose: the consumer (`chat-stream-reducer`'s\n * `applySseUsage`) re-validates every nested field with the legacy\n * truthiness/typeof gates, so a malformed frame degrades identically\n * to the pre-SSOT parser. Typing it would imply guarantees the wire\n * does not make. */\n breakdown?: unknown\n debug?: unknown\n}\n\n/** NATS TOKEN_USAGE chunk (camelCase backend shape). */\nexport interface TokenUsageEvent extends ChatStreamEventBase {\n type: 'token-usage'\n inputTokensSize: number\n outputTokensSize: number\n totalTokensSize: number\n contextSize: number\n}\n\nexport interface CompactionEvent extends ChatStreamEventBase {\n type: 'compaction'\n phase: 'start' | 'end'\n summary?: string\n}\n\nexport interface ErrorEvent extends ChatStreamEventBase {\n type: 'error'\n title: string\n details?: string\n}\n\n/** Non-assistant message on the stream (NATS): the user's own message\n * echo (`message-request`), an operator direct message, or a system\n * line. */\n/**\n * Dialog participant owner type. The two members below are the ones clients\n * BRANCH ON (admin-vs-not decides echo dedup and author styling); the union\n * stays open (`string & {}`) because the wire may carry other roles that the\n * client treats as \"not admin\". Always compare against `CHAT_OWNER_ADMIN`,\n * never a bare `'ADMIN'` literal — a typo in a literal silently disables\n * dedup instead of failing to compile.\n */\nexport type ChatOwnerType = 'ADMIN' | 'CLIENT' | (string & {})\n\n/** Canonical ADMIN owner-type token (see `ChatOwnerType`). */\nexport const CHAT_OWNER_ADMIN = 'ADMIN'\n\nexport interface ParticipantEvent extends ChatStreamEventBase {\n type: 'participant'\n kind: 'message-request' | 'direct-message' | 'system'\n text: string\n ownerType?: ChatOwnerType\n displayName?: string\n userId?: string\n contextItems?: Array<{ type: string; id: string; label: string }>\n}\n\nexport interface DialogClosedEvent extends ChatStreamEventBase {\n type: 'dialog-closed'\n}\n\nexport type ChatStreamEvent =\n | TurnStartEvent\n | TurnEndEvent\n | TextDeltaEvent\n | ThinkingDeltaEvent\n | StatusEvent\n | ToolExecutionEvent\n | ApprovalRequestEvent\n | ApprovalResolvedEvent\n | ChatMetadataEvent\n | UsageEvent\n | TokenUsageEvent\n | CompactionEvent\n | ErrorEvent\n | ParticipantEvent\n | DialogClosedEvent\n","/**\n * SSE wire-protocol encoders — the emit side of the framing contract in\n * `./frames.ts`. Server-safe (TextEncoder only). The hub's stream route\n * consumes these so emitter and decoder can never drift.\n */\n\nimport {\n FRAME_TERMINATOR,\n END_OF_LEADING,\n TRAILER_SENTINEL,\n type SseLeadingFrame,\n type SseTrailingUsageFrame,\n} from './frames'\n\nconst encoder = new TextEncoder()\n\n/** Matches every framing sentinel byte: `\\0`, `\\x1E`, `\\x1F`. THE one\n * regex — `stripSentinelBytes` is its only consumer. */\nconst SENTINEL_BYTES_RE = /[\\u0000\\u001E\\u001F]/g\n\n/**\n * Remove the SSE framing sentinel bytes (`\\0`, `\\x1E`, `\\x1F`) from model\n * text. Exported as a STANDALONE helper — not just folded into\n * `encodeTextDelta` — because producers must strip at the point where they\n * first take custody of the text, BEFORE any local accumulation.\n *\n * Concretely: the hub's `claude-util.ts` accumulates `state.answerText` for\n * persistence + telemetry. If stripping only happened at encode time, the\n * persisted/telemetered answer would diverge, character for character, from\n * the bytes the user actually received whenever the model echoes a control\n * byte. Both sides call this, so there is exactly ONE definition of \"which\n * bytes are framing\" in the whole system — do not re-declare the regex.\n *\n * Idempotent and per-character, so it distributes over concatenation:\n * `strip(a + b) === strip(a) + strip(b)` — safe to apply per-delta or on the\n * accumulated string interchangeably.\n */\nexport function stripSentinelBytes(text: string): string {\n return text.replace(SENTINEL_BYTES_RE, '')\n}\n\n/** Encode one leading frame: JSON + `\\0` terminator. */\nexport function encodeLeadingFrame(frame: SseLeadingFrame): Uint8Array {\n return encoder.encode(JSON.stringify(frame) + FRAME_TERMINATOR)\n}\n\n/** Encode the single `\\x1E` end-of-leading-frames sentinel. */\nexport function encodeEndOfLeading(): Uint8Array {\n return encoder.encode(END_OF_LEADING)\n}\n\n/**\n * Encode a raw answer-text delta. STRIPS the framing sentinel bytes via\n * `stripSentinelBytes` so model-echoed control bytes can no longer\n * mis-frame the stream (a literal `\\x1F` in the answer used to flip the\n * client into trailer mode and swallow the rest of the answer PLUS the real\n * usage trailer — characterized by golden fixture (d)). Forward-looking\n * encoder fix only; the decoder's behavior is unchanged.\n *\n * Producers that ALSO accumulate the text locally (persistence, telemetry)\n * must call `stripSentinelBytes` on their own copy — see its docblock.\n */\nexport function encodeTextDelta(text: string): Uint8Array {\n return encoder.encode(stripSentinelBytes(text))\n}\n\n/** Encode the trailing usage frame: `\\x1F` + JSON, no terminator\n * (runs to stream end). */\nexport function encodeTrailingUsageFrame(frame: SseTrailingUsageFrame): Uint8Array {\n return encoder.encode(TRAILER_SENTINEL + JSON.stringify(frame))\n}\n","/**\n * SSE wire-protocol decoder — a timer-free synchronous state machine,\n * mechanically extracted from `useSseChatAdapter`'s inline\n * `createDocStreamFn` parser. Byte-for-byte behavior parity with the\n * legacy parser is the contract (the golden fixtures in\n * `src/components/chat/hooks/__tests__/sse-stream-golden.test.ts` pin it\n * through the full hook path), including its quirks:\n *\n * - A leading `\\0`-terminated block that fails JSON.parse flips the\n * stream into text mode and the WHOLE buffer (including the `\\0`)\n * is emitted as answer text (legacy no-frame stream fallback). This\n * transition is marked `turn-start { implicit: true }`.\n * - In text mode only `\\x1F` is scanned — literal `\\0` / `\\x1E` bytes\n * pass through into the answer; the FIRST literal `\\x1F` flips into\n * trailer mode and everything after is captured as the trailer\n * (golden fixture (d) characterizes this mis-framing; the fix lives\n * in `encode.ts`'s sentinel stripping, NOT here).\n * - The `\\x1E` sentinel and the `\\x1F` trailer can arrive in ONE TCP\n * chunk (fixed-answer responses) — the post-sentinel slice is\n * re-scanned for the trailer sentinel.\n * - Multi-byte UTF-8 across chunk boundaries survives via a single\n * streaming TextDecoder (`{ stream: true }` on every push; no final\n * flush — a trailing partial code point is dropped, as legacy did).\n * - `end()` parses the accumulated trailer (malformed → silently\n * ignored) and drops any un-terminated leading buffer, as legacy did.\n * It is IDEMPOTENT (a deliberate deviation from legacy): repeat calls\n * emit nothing, so an adapter that ends in both its completion path\n * and its `finally` cannot double-count the usage frame.\n *\n * State flow: leading → (sentinel | parse-failure) → text → (\\x1F) →\n * trailer-accumulate → end().\n *\n * Server-safe: no React, no timers, TextDecoder only.\n */\n\nimport { FRAME_TERMINATOR, END_OF_LEADING, TRAILER_SENTINEL } from './frames'\nimport type { ChatStreamEvent } from './events'\n\nexport interface SseFrameDecoder {\n /** Feed raw response bytes; returns the events they produced. */\n push(bytes: Uint8Array): ChatStreamEvent[]\n /**\n * Signal end-of-stream; parses the trailing usage frame if present.\n * IDEMPOTENT — every call after the first returns `[]`. Adapters\n * routinely call this from BOTH their completion path and a `finally`,\n * and a re-emitted `usage`/`stage:'end'` event would double-count token\n * usage (displayed cost doubles).\n */\n end(): ChatStreamEvent[]\n}\n\n/**\n * Escape `<` so markdown renderers that pass HTML through (rehypeRaw)\n * don't treat XML-like tokens in Claude's thinking output as elements.\n * `<` → `<` preserves the visible character without breaking\n * blockquote `>` markers. Per-character, so it distributes over\n * concatenation: escape(a + b) === escape(a) + escape(b) — callers may\n * apply it per-delta or on the accumulated string interchangeably.\n */\nexport function escapeThinkingTags(text: string): string {\n return text.replace(/</g, '<')\n}\n\n/**\n * Map one parsed leading frame to normalized events, replicating the\n * legacy parser's else-if chain ORDER and its exact truthiness/typeof\n * gates. Frames that matched a branch but failed its inner validation\n * (e.g. `routing` without a string `routedComplexity`) produce NO event,\n * exactly like the legacy no-op.\n */\nfunction mapLeadingFrame(meta: any, out: ChatStreamEvent[]): void {\n if (meta.status === 'thinking') {\n out.push({ type: 'status', phase: 'thinking' })\n } else if (meta.kind === 'thinking-delta' && typeof meta.text === 'string') {\n // Wire is ALREADY delta — emit verbatim, append-only contract.\n out.push({ type: 'thinking-delta', text: meta.text })\n } else if (meta.kind === 'usage' && meta.stage === 'start') {\n out.push({\n type: 'usage',\n stage: 'start',\n input_tokens: meta.input_tokens,\n cache_read_input_tokens: meta.cache_read_input_tokens,\n cache_creation_input_tokens: meta.cache_creation_input_tokens,\n })\n } else if (meta.kind === 'decision_resolved' && typeof meta.action === 'string') {\n const status = meta.action === 'rejected' ? 'rejected' : 'approved'\n const toolName = typeof meta.tool_name === 'string' ? meta.tool_name : undefined\n const result = meta.result ?? null\n const card = meta.card ?? null\n out.push({\n type: 'approval-resolved',\n status,\n ok: meta.ok === true,\n willAutoContinue: meta.willAutoContinue === true,\n ...(toolName ? { toolName } : {}),\n ...(result ? { result } : {}),\n ...(card?.marker ? { marker: card.marker } : {}),\n ...(card?.ref ? { cardRef: card.ref } : {}),\n ...(card?.type ? { cardType: card.type } : {}),\n ...(typeof meta.receiptText === 'string' ? { receiptText: meta.receiptText } : {}),\n requestId: typeof meta.proposalId === 'string' ? meta.proposalId : undefined,\n })\n } else if (meta.kind === 'approval_request' && meta.proposalId) {\n const proposalId = String(meta.proposalId)\n const toolName = String(meta.toolName ?? 'tool')\n const headline =\n typeof meta.title === 'string' && meta.title.length > 0 ? meta.title : toolName\n const rawFields = Array.isArray(meta.fields)\n ? (meta.fields as Array<{ label?: string; value?: string }>)\n : []\n const fields: Array<{ label: string; value: string }> = []\n for (const f of rawFields) {\n if (!f || !f.label || !f.value) continue\n fields.push({ label: f.label, value: f.value })\n }\n out.push({\n type: 'approval-request',\n requestId: proposalId,\n approvalType: toolName,\n command: headline,\n fields,\n status: 'pending',\n })\n } else if (meta.kind === 'text-leading' && typeof meta.text === 'string') {\n out.push({ type: 'text-delta', text: meta.text, leading: true })\n } else if (meta.kind === 'tool_error') {\n const msg =\n typeof meta.message === 'string' && meta.message.length > 0\n ? meta.message\n : 'Could not complete the requested action right now.'\n out.push({ type: 'error', title: msg })\n } else if (meta.kind === 'routing') {\n if (typeof meta.routedComplexity === 'string') {\n out.push({\n type: 'metadata',\n routing: {\n routedComplexity: meta.routedComplexity,\n ...(typeof meta.routedModel === 'string' ? { routedModel: meta.routedModel } : {}),\n routedThinkingBudget:\n typeof meta.routedThinkingBudget === 'number' ? meta.routedThinkingBudget : null,\n },\n })\n }\n } else {\n // Catch-all metadata-ish frame. Raw values pass through UNVALIDATED\n // (possibly undefined) so the consumer can replicate the legacy\n // presence/truthiness gates exactly — including the `model`-presence\n // trigger whose value is never stored.\n out.push({\n type: 'metadata',\n sources: meta.sources,\n refs: meta.refs,\n provider: meta.provider,\n modelLabel: meta.modelLabel,\n modelName: meta.model,\n contextWindowMaxTokens: meta.contextWindowMaxTokens,\n scrollAnchor: meta.scrollAnchor,\n conversationId: meta.conversationId,\n })\n }\n}\n\nexport function createSseFrameDecoder(): SseFrameDecoder {\n const textDecoder = new TextDecoder()\n let buffer = ''\n let inText = false\n let inTrailer = false\n let trailerBuffer = ''\n let ended = false\n\n function push(bytes: Uint8Array): ChatStreamEvent[] {\n const out: ChatStreamEvent[] = []\n const chunk = textDecoder.decode(bytes, { stream: true })\n\n if (!inText) {\n buffer += chunk\n while (!inText) {\n const recIdx = buffer.indexOf(END_OF_LEADING)\n const nullIdx = buffer.indexOf(FRAME_TERMINATOR)\n if (recIdx !== -1 && (nullIdx === -1 || recIdx < nullIdx)) {\n inText = true\n out.push({ type: 'turn-start' })\n const after = buffer.slice(recIdx + 1)\n buffer = ''\n if (after) {\n // The `after` slice may ALSO contain the `\\x1F` trailing-\n // usage sentinel — common for fixed-answer responses where\n // the whole frame sequence arrives in ONE TCP chunk.\n const unitIdx = after.indexOf(TRAILER_SENTINEL)\n if (unitIdx === -1) {\n out.push({ type: 'text-delta', text: after })\n } else {\n const textBefore = after.slice(0, unitIdx)\n const trailerAfter = after.slice(unitIdx + 1)\n if (textBefore) {\n out.push({ type: 'text-delta', text: textBefore })\n }\n inTrailer = true\n trailerBuffer = trailerAfter\n }\n }\n break\n }\n if (nullIdx === -1) break // need more bytes\n const metaStr = buffer.slice(0, nullIdx)\n const remaining = buffer.slice(nullIdx + 1)\n let meta: any\n try {\n meta = JSON.parse(metaStr)\n } catch {\n // Not JSON — start of answer body. The WHOLE buffer (including\n // the `\\0`) becomes answer text; `implicit` tells consumers\n // this was the fallback path, not the `\\x1E` sentinel.\n inText = true\n out.push({ type: 'turn-start', implicit: true })\n if (buffer.length > 0) {\n out.push({ type: 'text-delta', text: buffer })\n buffer = ''\n }\n break\n }\n mapLeadingFrame(meta, out)\n buffer = remaining\n }\n } else if (inTrailer) {\n trailerBuffer += chunk\n } else {\n // Text mode: only the `\\x1F` trailer sentinel is scanned. The\n // unconditional emit (even for an empty decode of a partial\n // multi-byte code point) mirrors the legacy per-chunk yield.\n const sepIdx = chunk.indexOf(TRAILER_SENTINEL)\n if (sepIdx === -1) {\n out.push({ type: 'text-delta', text: chunk })\n } else {\n const before = chunk.slice(0, sepIdx)\n const after = chunk.slice(sepIdx + 1)\n if (before) out.push({ type: 'text-delta', text: before })\n inTrailer = true\n trailerBuffer = after\n }\n }\n return out\n }\n\n function end(): ChatStreamEvent[] {\n // Idempotency guard: a second end() must emit NOTHING. The trailer is\n // also cleared so no later push()/end() pair can replay it.\n if (ended) return []\n ended = true\n const out: ChatStreamEvent[] = []\n if (trailerBuffer.length > 0) {\n const raw = trailerBuffer\n trailerBuffer = ''\n try {\n const meta = JSON.parse(raw)\n if (meta.kind === 'usage' && (meta.stage === 'end' || meta.stage === 'display')) {\n out.push({\n type: 'usage',\n stage: 'end',\n input_tokens: meta.input_tokens,\n output_tokens: meta.output_tokens,\n cache_read_input_tokens: meta.cache_read_input_tokens,\n cache_creation_input_tokens: meta.cache_creation_input_tokens,\n hit_rate_pct: meta.hit_rate_pct,\n telemetry: meta.telemetry,\n breakdown: meta.breakdown,\n debug: meta.debug,\n })\n }\n } catch {\n // Malformed trailer — silently ignore (legacy parity).\n }\n }\n return out\n }\n\n return { push, end }\n}\n","/**\n * Message-related types\n * Contains all message structures, segments, and content types\n */\n\nimport type { AssistantType, AuthorType, ChatApprovalStatus, MessageOwner } from './chat.types'\n\n// ========== Message Type Definitions ==========\n\nexport const MESSAGE_TYPE = {\n TEXT: 'TEXT',\n THINKING: 'THINKING',\n EXECUTING_TOOL: 'EXECUTING_TOOL',\n EXECUTED_TOOL: 'EXECUTED_TOOL',\n APPROVAL_REQUEST: 'APPROVAL_REQUEST',\n APPROVAL_RESULT: 'APPROVAL_RESULT',\n ERROR: 'ERROR',\n MESSAGE_START: 'MESSAGE_START',\n MESSAGE_END: 'MESSAGE_END',\n MESSAGE_REQUEST: 'MESSAGE_REQUEST',\n AI_METADATA: 'AI_METADATA',\n TOKEN_USAGE: 'TOKEN_USAGE',\n CONTEXT_COMPACTION_START: 'CONTEXT_COMPACTION_START',\n CONTEXT_COMPACTION_END: 'CONTEXT_COMPACTION_END',\n DIRECT_MESSAGE: 'DIRECT_MESSAGE',\n SYSTEM: 'SYSTEM',\n DIALOG_CLOSED: 'DIALOG_CLOSED',\n} as const\n\nexport type MessageType = typeof MESSAGE_TYPE[keyof typeof MESSAGE_TYPE]\n\n// ========== Scroll Anchor (per-message render hint) ==========\n\n/** Per-message viewport-positioning hint sent on the per-turn metadata\n * leading frame at the START of every assistant response. The chat\n * message-list reads it to override the default `use-stick-to-bottom`\n * tail behaviour for a single message. Field is OPTIONAL — when omitted\n * (or set to `'bottom'`) the chat tails as today. Only `'top'` opts in\n * to the alternative behaviour (used by display-action answers whose\n * body is a long article and should be read top-down). */\nexport const SCROLL_ANCHOR = { TOP: 'top', BOTTOM: 'bottom' } as const\n\nexport type ScrollAnchor = typeof SCROLL_ANCHOR[keyof typeof SCROLL_ANCHOR]\n\n// ========== Tool Execution Types ==========\n\nexport interface ToolExecutionData {\n type: 'EXECUTING_TOOL' | 'EXECUTED_TOOL'\n integratedToolType: string\n toolFunction: string\n /** Backend-issued human-readable title (mirrors `PendingToolCallData.toolTitle`). */\n toolTitle?: string\n /**\n * Backend-issued human-readable explanation of what the tool is doing and why\n * (mirrors `PendingToolCallData.toolExplanation`). Only sent on `EXECUTING_TOOL`;\n * the accumulator restores it onto the merged `EXECUTED_TOOL` segment.\n */\n toolExplanation?: string\n parameters?: Record<string, any>\n result?: string\n success?: boolean\n /**\n * Backend-issued id (matches `PendingToolCallData.toolExecutionRequestId`).\n * When present, lets the accumulator merge this execution event into the\n * matching approval batch row instead of emitting a standalone segment.\n */\n toolExecutionRequestId?: string\n}\n\n/**\n * Snapshot of an in-flight tool kept between the `EXECUTING_TOOL` and\n * `EXECUTED_TOOL` events. The backend only sends `toolTitle` on\n * `EXECUTING_TOOL`; carrying this state lets the accumulator restore it onto\n * the merged `EXECUTED_TOOL` segment instead of falling back to the raw\n * `toolFunction`.\n */\nexport interface ExecutingToolState {\n integratedToolType: string\n toolFunction: string\n /** Mirrors {@link ToolExecutionData.toolTitle}; absent on `EXECUTED_TOOL`. */\n toolTitle?: string\n /** Mirrors {@link ToolExecutionData.toolExplanation}; absent on `EXECUTED_TOOL`. */\n toolExplanation?: string\n parameters?: Record<string, any>\n}\n\n// ========== Approval Request Types ==========\n\nexport interface ApprovalRequestField {\n /** Short label — e.g. \"Subject\", \"Priority\". Rendered in a muted\n * caps style above the value. */\n label: string\n /** Free-text value. Wraps and line-breaks are preserved\n * (`whitespace-pre-wrap`). */\n value: string\n}\n\nexport interface ApprovalRequestData {\n command: string\n /** Structured field list — preferred over `explanation`. When set,\n * the approval card renders a vertical label/value stack with\n * proper spacing. Falls back to `explanation` (a single paragraph)\n * when omitted. Keep BOTH when you want hosts on older lib\n * versions to still see the prose; new hosts should send only\n * `fields`. */\n fields?: ApprovalRequestField[]\n explanation?: string\n icon?: React.ReactNode\n requestId?: string\n approvalRequestId?: string\n approvalType?: string\n}\n\nexport interface ApprovalResultData {\n approvalRequestId: string\n approved: boolean\n approvalType?: string\n /** Display name of the user who resolved the request; null/absent for system actions. */\n resolvedByName?: string | null\n}\n\n/**\n * Single tool call inside a batch approval request.\n * Mirrors backend PendingToolCallDto.\n */\nexport interface PendingToolCallData {\n toolExecutionRequestId: string\n toolName: string\n toolTitle?: string\n toolExplanation?: string\n toolType?: string\n requiresApproval: boolean\n approvalType?: string | null\n toolCallArguments?: Record<string, any> | null\n}\n\n/**\n * Per-tool execution state inside an approval batch.\n * Populated by EXECUTING_TOOL / EXECUTED_TOOL chunks that carry a\n * `toolExecutionRequestId` matching one of the batch's tool calls.\n */\nexport interface ApprovalBatchExecutionState {\n status: 'executing' | 'done'\n result?: string\n success?: boolean\n}\n\nexport interface ApprovalBatchData {\n approvalRequestId: string\n /** Highest approval type required across the batch (e.g. ADMIN beats CLIENT). */\n approvalType: string\n toolCalls: PendingToolCallData[]\n /**\n * Keyed by `PendingToolCallData.toolExecutionRequestId`. Absent before\n * approval; rows without an entry render as \"queued\" (loader) once the\n * batch itself is approved.\n */\n executions?: Record<string, ApprovalBatchExecutionState>\n}\n\n// ========== Message Segment Types ==========\n\nexport type TextSegment = {\n type: 'text'\n text: string\n}\n\nexport type ThinkingSegment = {\n type: 'thinking'\n text: string\n}\n\nexport type ToolExecutionSegment = {\n type: 'tool_execution'\n data: ToolExecutionData\n}\n\nexport type ApprovalRequestSegment = {\n type: 'approval_request'\n data: ApprovalRequestData & { approvalType?: string }\n status?: ChatApprovalStatus\n /** Display name of the user who resolved the request; baked into the client\n * variant's full-text status pill (\"Approved by {name}\"). */\n resolvedByName?: string | null\n onApprove?: (requestId?: string) => void | Promise<void>\n onReject?: (requestId?: string) => void | Promise<void>\n}\n\nexport type ApprovalBatchSegment = {\n type: 'approval_batch'\n data: ApprovalBatchData\n status?: ChatApprovalStatus\n /** Display name of the user who resolved the request; set when the batch is resolved (null/absent for system actions). */\n resolvedByName?: string | null\n onApprove?: (requestId?: string) => void | Promise<void>\n onReject?: (requestId?: string) => void | Promise<void>\n}\n\nexport type ErrorSegment = {\n type: 'error'\n title: string\n details?: string\n}\n\nexport type ContextCompactionSegment = {\n type: 'context_compaction'\n status: 'started' | 'completed'\n summary?: string\n}\n\nexport type MessageSegment = TextSegment | ThinkingSegment | ToolExecutionSegment | ApprovalRequestSegment | ApprovalBatchSegment | ErrorSegment | ContextCompactionSegment\n\nexport type MessageContent = string | MessageSegment[]\n\n// ========== Message Data Types (from GraphQL/API) ==========\n\nexport interface MessageDataBase {\n type: MessageType\n}\n\nexport interface TextMessageData extends MessageDataBase {\n type: 'TEXT'\n text?: string\n}\n\nexport interface ThinkingMessageData extends MessageDataBase {\n type: 'THINKING'\n text?: string\n}\n\nexport interface ExecutingToolMessageData extends MessageDataBase {\n type: 'EXECUTING_TOOL'\n integratedToolType?: string\n toolFunction?: string\n /** Backend-issued human-readable title (wire field, mirrors `ChunkData.title`). */\n title?: string\n /** Backend-issued human-readable explanation (what/why) of the tool call. */\n toolExplanation?: string\n parameters?: Record<string, any>\n toolExecutionRequestId?: string\n}\n\nexport interface ExecutedToolMessageData extends MessageDataBase {\n type: 'EXECUTED_TOOL'\n integratedToolType?: string\n toolFunction?: string\n /** Backend-issued human-readable title (wire field, mirrors `ChunkData.title`). */\n title?: string\n parameters?: Record<string, any>\n result?: string\n success?: boolean\n toolExecutionRequestId?: string\n}\n\nexport interface ApprovalRequestMessageData extends MessageDataBase {\n type: 'APPROVAL_REQUEST'\n approvalRequestId?: string\n approvalType?: string\n command?: string\n explanation?: string\n /** Present when the approval is a batch of tool calls (new format). */\n toolCalls?: PendingToolCallData[]\n}\n\nexport interface ApprovalResultMessageData extends MessageDataBase {\n type: 'APPROVAL_RESULT'\n approvalRequestId?: string\n approved?: boolean\n approvalType?: string\n /** Display name of the user who resolved the request; null/absent for system actions. */\n resolvedByName?: string | null\n}\n\nexport interface ErrorMessageData extends MessageDataBase {\n type: 'ERROR'\n error?: string\n details?: string\n}\n\nexport interface AIMetadataMessageData extends MessageDataBase {\n type: 'AI_METADATA'\n modelName?: string\n providerName?: string\n provider?: string\n contextWindow?: number\n}\n\nexport interface TokenUsageData {\n inputTokensSize: number\n outputTokensSize: number\n totalTokensSize: number\n contextSize: number\n}\n\nexport interface SystemMessageData extends MessageDataBase {\n type: 'SYSTEM'\n text?: string\n}\n\nexport interface ContextCompactionStartMessageData extends MessageDataBase {\n type: 'CONTEXT_COMPACTION_START'\n}\n\nexport interface ContextCompactionEndMessageData extends MessageDataBase {\n type: 'CONTEXT_COMPACTION_END'\n summary?: string\n}\n\nexport type MessageData =\n | TextMessageData\n | ThinkingMessageData\n | ExecutingToolMessageData\n | ExecutedToolMessageData\n | ApprovalRequestMessageData\n | ApprovalResultMessageData\n | ErrorMessageData\n | AIMetadataMessageData\n | SystemMessageData\n | ContextCompactionStartMessageData\n | ContextCompactionEndMessageData\n\n// ========== Historical Message Types ==========\n\nexport interface HistoricalMessage {\n id: string\n dialogId?: string\n chatType?: string\n createdAt: string\n owner?: MessageOwner\n messageData?: MessageData | MessageData[]\n /** Persisted stream sequence of this row's last chunk (the backend's\n * `lastChunkStreamSeq`). Passed through to the processed message's\n * `streamSeq` so `mergeHistoryWithRealtime` can decide coverage per-role\n * (a synthetic is covered only by a persisted row of its OWN role reaching\n * its seq). Optional — absent for rows the backend doesn't stamp (e.g. user\n * MESSAGE_REQUEST rows), which then don't participate in seq coverage. */\n lastChunkStreamSeq?: number | null\n}\n\n// ========== Processed Message Types ==========\n\nexport interface ProcessedMessage {\n id: string\n role: 'user' | 'assistant' | 'error' // Limited to display roles\n content: MessageContent\n name?: string\n assistantType?: AssistantType\n authorType?: AuthorType\n timestamp: Date\n avatar?: string\n /** Persisted last-chunk stream sequence carried through from\n * `HistoricalMessage.lastChunkStreamSeq` (for assistant turns: the MAX\n * across the grouped rows). Hosts stamp it onto the rendered message's\n * `streamSeq` so the history/realtime merge can do per-role seq coverage.\n * Absent when the source row(s) carried no seq. */\n streamSeq?: number\n}\n\n// ========== Base Message Interface ==========\n\nimport type { ChatRef as MessageChatRef } from '../chat-ref.types'\nimport type { ChatContextItem } from './context-item.types'\n\nexport interface Message {\n id: string\n role: 'user' | 'assistant' | 'error' // Limited to display roles\n content: MessageContent\n name?: string\n assistantType?: AssistantType\n authorType?: AuthorType\n timestamp?: Date\n avatar?: string | null\n /** Highest CONTENT chunk streamSeq that composed this message. Stamped on\n * realtime synthetics so `mergeHistoryWithRealtime` can decide history\n * coverage per-message (see `MergeableChatMessage.streamSeq`). */\n streamSeq?: number\n /** Per-row metadata for inline entity-card rendering on this message\n * (v6.1 §B.2.6). Keyed by `<documentType>:<primaryKey>`. Optional —\n * user messages and legacy turns omit this field. The host's\n * `renderEntityCard` callback resolves keys to inline components. */\n chatRefs?: Record<string, MessageChatRef>\n /** Entity-context items attached to this (user) message via the composer's\n * context picker. When present the message bubble renders the context\n * chips beneath its text (Figma node 31:28709). Optional — omitted for\n * assistant messages and turns sent without context. */\n contextItems?: ChatContextItem[]\n /** Per-message viewport-positioning hint. OPTIONAL — when omitted (the\n * default for every LLM Q&A / browse / search / find / Discuss path)\n * the chat tails as today via `use-stick-to-bottom`. Only `'top'` opts\n * in to the alternative top-anchor behaviour (display-action answers\n * whose body is a long article). The server is the sole decision-\n * maker — set on the metadata leading frame. */\n scrollAnchor?: ScrollAnchor\n /** When true the message is part of the API conversation history (sent\n * to the LLM so it has context) but is NOT rendered in the chat UI.\n *\n * Used for \"synthetic continuation\" turns: when the user clicks Approve\n * on a tool proposal, the host auto-fires a follow-up `sendMessage`\n * with `hidden: true` carrying a directive like \"the user just\n * approved <tool>; ask follow-up questions per protocol\". The LLM's\n * response IS rendered (as a normal assistant message); only the\n * trigger prompt is suppressed so the chat reads naturally:\n *\n * user: \"open a ticket\"\n * assistant: preamble + approval card\n * [user clicks Approve]\n * assistant: \"Now to triage faster, can you share...\" ← auto-fires\n *\n * Without this flag the trigger prompt would surface as a confusing\n * bubble like \"(continue per protocol)\" between the approval card\n * and the AI's follow-up. */\n hidden?: boolean\n}","/**\n * NATS chunk → normalized `ChatStreamEvent` decoder.\n *\n * THE live NATS reading path — the ONLY chunk parser in the codebase. Every\n * consumer (this lib's `useNatsChatAdapter`, the hub, the product app) feeds\n * raw chunks through `decodeNatsChunk` into `createChatStreamReducer`. The\n * legacy `components/chat/utils/chunk-parser.ts` (`parseChunkToAction`) that\n * this module superseded was DELETED — do not reintroduce a second decoder.\n *\n * Chunks map onto the transport-agnostic event union, with the JetStream\n * `streamSeq` lifted into the `seq` envelope (the reducer's idempotency gate\n * keys off it).\n *\n * Behavior is pinned by `__tests__/nats-decoder-golden.test.ts`.\n *\n * Server-safe: no React, no browser APIs.\n */\n\nimport { MESSAGE_TYPE } from '../components/chat/types/message.types'\nimport type { ApprovalToolCall, ChatStreamEvent } from './events'\n\n/** Minimal structural view of a NATS chunk (see `ChunkData` in\n * `src/components/chat/types/network.types.ts`). */\ntype NatsChunk = Record<string, any>\n\n/** Coerce the wire's `toolCalls[]` into the batch-approval shape, dropping\n * non-object entries and defaulting every field. */\nfunction normalizeToolCalls(raw: unknown): ApprovalToolCall[] {\n if (!Array.isArray(raw)) return []\n return raw\n .filter((item): item is Record<string, any> => !!item && typeof item === 'object')\n .map((item) => ({\n toolExecutionRequestId: String(item.toolExecutionRequestId ?? ''),\n toolName: String(item.toolName ?? ''),\n toolTitle: typeof item.toolTitle === 'string' ? item.toolTitle : undefined,\n toolExplanation:\n typeof item.toolExplanation === 'string' ? item.toolExplanation : undefined,\n toolType: typeof item.toolType === 'string' ? item.toolType : undefined,\n requiresApproval: item.requiresApproval === true,\n approvalType: typeof item.approvalType === 'string' ? item.approvalType : null,\n toolCallArguments:\n item.toolCallArguments && typeof item.toolCallArguments === 'object'\n ? (item.toolCallArguments as Record<string, any>)\n : null,\n }))\n}\n\n/**\n * Parse one raw NATS chunk into a normalized event. Returns `null` for\n * unknown/malformed chunks — an unrecognized `type`, a missing required\n * field, or a non-object payload are all tolerated as no-ops rather than\n * throwing, so a backend that adds a chunk type can't break the stream.\n */\nexport function decodeNatsChunk(chunk: unknown): ChatStreamEvent | null {\n if (!chunk || typeof chunk !== 'object') return null\n\n const data = chunk as NatsChunk\n const type = String(data.type || '')\n // JetStream stream sequence → the generic `seq` envelope.\n const seq: { seq?: number } =\n typeof data.streamSeq === 'number' ? { seq: data.streamSeq } : {}\n\n switch (type) {\n case MESSAGE_TYPE.MESSAGE_START:\n return { type: 'turn-start', ...seq }\n\n case MESSAGE_TYPE.MESSAGE_END:\n return { type: 'turn-end', ...seq }\n\n case MESSAGE_TYPE.AI_METADATA: {\n const providerName = data.providerName || data.provider\n if (typeof data.modelName === 'string' && typeof providerName === 'string') {\n return {\n type: 'metadata',\n modelLabel: data.modelDisplayName,\n modelName: data.modelName,\n provider: providerName,\n contextWindowMaxTokens:\n typeof data.contextWindow === 'number' ? data.contextWindow : 0,\n ...seq,\n }\n }\n return null\n }\n\n case MESSAGE_TYPE.TEXT:\n if (typeof data.text === 'string') {\n return { type: 'text-delta', text: data.text, ...seq }\n }\n return null\n\n case MESSAGE_TYPE.THINKING:\n if (typeof data.text === 'string') {\n return { type: 'thinking-delta', text: data.text, ...seq }\n }\n return null\n\n case MESSAGE_TYPE.EXECUTING_TOOL:\n return {\n type: 'tool-execution',\n data: {\n type: 'EXECUTING_TOOL',\n integratedToolType: data.integratedToolType || '',\n toolFunction: data.toolFunction || '',\n toolTitle: typeof data.title === 'string' ? data.title : undefined,\n parameters: data.parameters,\n toolExecutionRequestId:\n typeof data.toolExecutionRequestId === 'string'\n ? data.toolExecutionRequestId\n : undefined,\n },\n ...seq,\n }\n\n case MESSAGE_TYPE.EXECUTED_TOOL:\n return {\n type: 'tool-execution',\n data: {\n type: 'EXECUTED_TOOL',\n integratedToolType: data.integratedToolType || '',\n toolFunction: data.toolFunction || '',\n toolTitle: typeof data.title === 'string' ? data.title : undefined,\n parameters: data.parameters,\n result: data.result,\n success: data.success,\n toolExecutionRequestId:\n typeof data.toolExecutionRequestId === 'string'\n ? data.toolExecutionRequestId\n : undefined,\n },\n ...seq,\n }\n\n case MESSAGE_TYPE.APPROVAL_REQUEST: {\n const requestId = data.approvalRequestId || data.approval_request_id || ''\n const approvalType = data.approvalType || 'USER'\n const toolCalls = normalizeToolCalls(data.toolCalls)\n\n if (toolCalls.length > 0) {\n return { type: 'approval-request', requestId, approvalType, toolCalls, ...seq }\n }\n\n return {\n type: 'approval-request',\n requestId,\n approvalType,\n command: data.command || '',\n explanation: data.explanation,\n ...seq,\n }\n }\n\n case MESSAGE_TYPE.APPROVAL_RESULT: {\n // Realtime chunks carry the resolver's name as `displayName`; the\n // persisted GraphQL message exposes the same value as\n // `resolvedByName`. Accept either so realtime and history-replay\n // render \"by {name}\" identically.\n const resolvedByName =\n typeof data.resolvedByName === 'string'\n ? data.resolvedByName\n : typeof data.displayName === 'string'\n ? data.displayName\n : undefined\n return {\n type: 'approval-resolved',\n requestId: data.approvalRequestId || data.approval_request_id || '',\n status: data.approved === true ? 'approved' : 'rejected',\n approvalType: data.approvalType || 'CLIENT',\n resolvedByName,\n ...seq,\n }\n }\n\n case MESSAGE_TYPE.ERROR:\n return {\n type: 'error',\n title: data.error || 'An error occurred',\n details: data.details,\n ...seq,\n }\n\n case MESSAGE_TYPE.MESSAGE_REQUEST:\n return {\n type: 'participant',\n kind: 'message-request',\n text: String(data.text || ''),\n ownerType: typeof data.ownerType === 'string' ? data.ownerType : undefined,\n displayName: typeof data.displayName === 'string' ? data.displayName : undefined,\n userId: typeof data.userId === 'string' ? data.userId : undefined,\n // Wire shape carries no label; fall back to the id (parity with\n // the history path in `process-historical-messages.ts`).\n contextItems: Array.isArray(data.contextItems)\n ? (data.contextItems as Array<{ type?: unknown; id?: unknown }>)\n .filter((it) => typeof it?.type === 'string' && typeof it?.id === 'string')\n .map((it) => ({\n type: it.type as string,\n id: it.id as string,\n label: it.id as string,\n }))\n : undefined,\n ...seq,\n }\n\n case MESSAGE_TYPE.TOKEN_USAGE:\n return {\n type: 'token-usage',\n inputTokensSize: data.inputTokensSize ?? 0,\n outputTokensSize: data.outputTokensSize ?? 0,\n totalTokensSize: data.totalTokensSize ?? 0,\n contextSize: data.contextSize ?? 0,\n ...seq,\n }\n\n case MESSAGE_TYPE.CONTEXT_COMPACTION_START:\n return { type: 'compaction', phase: 'start', ...seq }\n\n case MESSAGE_TYPE.CONTEXT_COMPACTION_END:\n return {\n type: 'compaction',\n phase: 'end',\n summary: typeof data.text === 'string' ? data.text : undefined,\n ...seq,\n }\n\n case MESSAGE_TYPE.SYSTEM:\n if (typeof data.text === 'string') {\n return { type: 'participant', kind: 'system', text: data.text, ...seq }\n }\n return null\n\n case MESSAGE_TYPE.DIRECT_MESSAGE:\n if (typeof data.text === 'string') {\n return {\n type: 'participant',\n kind: 'direct-message',\n text: data.text,\n ownerType: typeof data.ownerType === 'string' ? data.ownerType : undefined,\n displayName:\n typeof data.displayName === 'string' ? data.displayName : undefined,\n userId: typeof data.userId === 'string' ? data.userId : undefined,\n ...seq,\n }\n }\n return null\n\n case MESSAGE_TYPE.DIALOG_CLOSED:\n return { type: 'dialog-closed', ...seq }\n\n default:\n return null\n }\n}\n","/**\n * `normalizeIpForBucketKey` — THE cross-repo normalizer for turning a raw\n * client-IP candidate (`x-forwarded-for` hop, socket remote address, proxy\n * header) into a stable rate-limit / dedup bucket key.\n *\n * WHY IT LIVES HERE: producer and consumer sit in DIFFERENT repos (the app\n * emits the candidate, the hub buckets it) and each had grown its own\n * normalizer. They disagreed — one unwrapped `::ffff:1.2.3.4` to the bare\n * IPv4 and stripped `%zone`, the other kept the zone and only lower-cased the\n * mapped form — so ONE visitor could land in TWO buckets depending on which\n * side normalized. Both repos already depend on this package, and\n * `./chat-protocol` is its server-safe subpath (no React, no browser APIs),\n * so this is the one place both sides can share.\n *\n * Contract:\n * - input longer than `IP_BUCKET_KEY_MAX_LENGTH` → `null` (an unbounded\n * header must never become an unbounded map key);\n * - `[…]` brackets and a trailing `]:port` are stripped, as is a bare\n * `:port` on an IPv4 (`203.0.113.4:8080`) — an unbracketed IPv6 with a\n * bare port stays ambiguous and is not stripped;\n * - a `%zone` suffix is stripped (link-local scope is per-host, not part of\n * the peer's identity);\n * - IPv4-mapped IPv6 (`::ffff:203.0.113.4`) collapses to the bare IPv4, so\n * the same peer buckets identically over either stack;\n * - IPv6 is lower-cased;\n * - IPv4 octets are range-checked and REJECTED when zero-padded (`.04`\n * would otherwise bucket separately from `.4`), and IPv6 is\n * charset/shape-checked (one `::` at most, ≤8 groups, an embedded IPv4\n * only in the last group, no dangling separator); anything else returns\n * `null` rather than a junk bucket key.\n *\n * It does NOT canonicalize IPv6 zero-compression (`2001:db8::1` vs\n * `2001:0db8:0:0:0:0:0:1`) — peers do not spell their own address two ways\n * within one deployment, and a full expander is more surface than the bucket\n * key warrants.\n */\n\n/** Longest accepted candidate. A full IPv6 + zone fits well inside this. */\nexport const IP_BUCKET_KEY_MAX_LENGTH = 64\n\nfunction isIpv4(value: string): boolean {\n const parts = value.split('.')\n if (parts.length !== 4) return false\n for (const part of parts) {\n if (!/^\\d{1,3}$/.test(part)) return false\n // Leading zeros are a SECOND spelling of the same address (`203.0.113.04`),\n // so accepting them verbatim splits one peer across two buckets. Reject\n // rather than canonicalize: no legitimate emitter zero-pads, and some\n // resolvers read a `0`-prefixed octet as octal, i.e. it is not even\n // reliably the same address.\n if (part.length > 1 && part.startsWith('0')) return false\n if (Number(part) > 255) return false\n }\n return true\n}\n\nfunction isIpv6(value: string): boolean {\n if (!value.includes(':')) return false\n // Charset gate first: hex digits, separators, and the dots of a trailing\n // embedded IPv4. Anything else (a hostname, a header injection) is out.\n if (!/^[0-9a-f:.]+$/.test(value)) return false\n if (value.includes(':::')) return false\n // A dangling separator (`2001:db8::1:`) leaves an EMPTY trailing group that\n // is not part of a `::` compression — malformed, not an address.\n if (value.endsWith(':') && !value.endsWith('::')) return false\n if (value.startsWith(':') && !value.startsWith('::')) return false\n const compressions = value.split('::').length - 1\n if (compressions > 1) return false\n const groups = value.split(':')\n if (groups.length > 8) return false\n for (let i = 0; i < groups.length; i += 1) {\n const group = groups[i]\n if (group === '') continue\n if (group.includes('.')) {\n // An embedded IPv4 occupies the LAST two groups; anywhere else\n // (`1.2.3.4::1`) it is malformed.\n if (i !== groups.length - 1) return false\n if (!isIpv4(group)) return false\n continue\n }\n if (!/^[0-9a-f]{1,4}$/.test(group)) return false\n }\n // Uncompressed form must be exactly 8 groups (a trailing embedded IPv4\n // occupies two, so 7 written groups is also complete).\n if (compressions === 0) {\n const embedsIpv4 = groups[groups.length - 1]?.includes('.') ?? false\n if (groups.length !== (embedsIpv4 ? 7 : 8)) return false\n }\n return true\n}\n\n/**\n * Normalize one IP candidate to its canonical bucket key, or `null` when the\n * value is not a usable address.\n */\nexport function normalizeIpForBucketKey(value: string): string | null {\n if (typeof value !== 'string') return null\n let candidate = value.trim()\n if (candidate === '' || candidate.length > IP_BUCKET_KEY_MAX_LENGTH) return null\n\n // `[2001:db8::1]` / `[::1]:443` — the bracketed forms a proxy emits so the\n // port is unambiguous.\n if (candidate.startsWith('[')) {\n const close = candidate.indexOf(']')\n if (close === -1) return null\n const trailer = candidate.slice(close + 1)\n if (trailer !== '' && !/^:\\d{1,5}$/.test(trailer)) return null\n candidate = candidate.slice(1, close)\n }\n\n // `%eth0` / `%25eth0` scope id — host-local, never part of peer identity.\n const zone = candidate.indexOf('%')\n if (zone !== -1) candidate = candidate.slice(0, zone)\n if (candidate === '') return null\n\n // UNBRACKETED `203.0.113.4:8080` — Azure App Service / Front Door and several\n // CDNs write the client hop that way. Rejecting it left the caller with NO\n // candidate at all, collapsing every visitor into the single egress bucket:\n // exactly the silent regression this module exists to prevent. Stripped ONLY\n // when the remainder is a valid IPv4; an unbracketed IPv6 with a bare port\n // (`::1:443`) is genuinely ambiguous — `:443` is equally a final group — so\n // that shape is left to the IPv6 path.\n const portSplit = candidate.lastIndexOf(':')\n if (portSplit > 0 && /^\\d{1,5}$/.test(candidate.slice(portSplit + 1))) {\n const head = candidate.slice(0, portSplit)\n if (isIpv4(head)) candidate = head\n }\n\n if (isIpv4(candidate)) return candidate\n\n const lowered = candidate.toLowerCase()\n\n // IPv4-mapped IPv6 → the bare IPv4 (same peer, one bucket). EVERY spelling\n // is handled: the compressed `::ffff:1.2.3.4` that dual-stack listeners\n // actually emit, the written-out `0:0:0:0:0:ffff:1.2.3.4` that a hop doing\n // its own (non-compressing) formatting can produce, and the ZERO-PADDED\n // `0000:0000:0000:0000:0000:ffff:1.2.3.4` that a fixed-width formatter\n // produces — leading zeros in an IPv6 group are purely cosmetic, so all\n // three name the same peer. Matching only some of them would split one peer\n // across two buckets — the exact failure this module exists to prevent.\n const mapped = /^(?:(?:0{1,4}:){5}|::)ffff:(\\d{1,3}(?:\\.\\d{1,3}){3})$/.exec(lowered)\n if (mapped) return isIpv4(mapped[1]) ? mapped[1] : null\n\n if (isIpv6(lowered)) return lowered\n return null\n}\n","/**\n * `envFlagEnabled` — THE cross-repo predicate for reading a boolean env flag.\n *\n * WHY IT LIVES HERE: the same flag is read on BOTH sides of the guide-chat\n * seam and each side had grown its own reading of it. The hub parsed the\n * value (`'0'` / `'false'` / `'off'` mean OFF); the producing app used bare\n * `Boolean(process.env.X)`, under which every non-empty string — including\n * `'0'` and `'false'` — is TRUE.\n *\n * That divergence failed OPEN on the one flag that gates a security boundary.\n * `TRUSTED_INGRESS_SETS_REAL_IP` is an operator's assertion that a reverse\n * proxy OVERWRITES the client-IP headers; without it those headers are\n * attacker-writable and must not be read. An operator writing `=0` to mean\n * \"off\" got the hub honoring that while the producer read `x-real-ip` /\n * `x-forwarded-for` anyway and forwarded the value as `x-chat-ip`, which the\n * hub then trusts verbatim under the service token. A rate-limit-bucket\n * spoof, reachable through a plausible operator typo.\n *\n * Both repos already depend on this package and `./chat-protocol` is its\n * server-safe subpath (no React, no browser APIs), so this is the one place\n * both sides can share — same reasoning that moved `normalizeIpForBucketKey`\n * here. Keep it as ONE definition: a second copy is what caused the drift.\n *\n * Contract:\n * - unset, empty, or whitespace-only → `false`;\n * - `'0'`, `'false'`, `'off'` → `false` (case- and\n * surrounding-whitespace-insensitive);\n * - any other non-empty value → `true`.\n *\n * `process.env` is read PER CALL, never module-hoisted, so tests, preview and\n * prod all observe the live value rather than whatever was present at\n * module-eval time.\n */\nexport function envFlagEnabled(name: string): boolean {\n const raw = process.env[name]\n if (!raw) return false\n const v = raw.trim().toLowerCase()\n return v !== '' && v !== '0' && v !== 'false' && v !== 'off'\n}\n"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `normalizeIpForBucketKey` — THE cross-repo normalizer for turning a raw
|
|
3
|
+
* client-IP candidate (`x-forwarded-for` hop, socket remote address, proxy
|
|
4
|
+
* header) into a stable rate-limit / dedup bucket key.
|
|
5
|
+
*
|
|
6
|
+
* WHY IT LIVES HERE: producer and consumer sit in DIFFERENT repos (the app
|
|
7
|
+
* emits the candidate, the hub buckets it) and each had grown its own
|
|
8
|
+
* normalizer. They disagreed — one unwrapped `::ffff:1.2.3.4` to the bare
|
|
9
|
+
* IPv4 and stripped `%zone`, the other kept the zone and only lower-cased the
|
|
10
|
+
* mapped form — so ONE visitor could land in TWO buckets depending on which
|
|
11
|
+
* side normalized. Both repos already depend on this package, and
|
|
12
|
+
* `./chat-protocol` is its server-safe subpath (no React, no browser APIs),
|
|
13
|
+
* so this is the one place both sides can share.
|
|
14
|
+
*
|
|
15
|
+
* Contract:
|
|
16
|
+
* - input longer than `IP_BUCKET_KEY_MAX_LENGTH` → `null` (an unbounded
|
|
17
|
+
* header must never become an unbounded map key);
|
|
18
|
+
* - `[…]` brackets and a trailing `]:port` are stripped, as is a bare
|
|
19
|
+
* `:port` on an IPv4 (`203.0.113.4:8080`) — an unbracketed IPv6 with a
|
|
20
|
+
* bare port stays ambiguous and is not stripped;
|
|
21
|
+
* - a `%zone` suffix is stripped (link-local scope is per-host, not part of
|
|
22
|
+
* the peer's identity);
|
|
23
|
+
* - IPv4-mapped IPv6 (`::ffff:203.0.113.4`) collapses to the bare IPv4, so
|
|
24
|
+
* the same peer buckets identically over either stack;
|
|
25
|
+
* - IPv6 is lower-cased;
|
|
26
|
+
* - IPv4 octets are range-checked and REJECTED when zero-padded (`.04`
|
|
27
|
+
* would otherwise bucket separately from `.4`), and IPv6 is
|
|
28
|
+
* charset/shape-checked (one `::` at most, ≤8 groups, an embedded IPv4
|
|
29
|
+
* only in the last group, no dangling separator); anything else returns
|
|
30
|
+
* `null` rather than a junk bucket key.
|
|
31
|
+
*
|
|
32
|
+
* It does NOT canonicalize IPv6 zero-compression (`2001:db8::1` vs
|
|
33
|
+
* `2001:0db8:0:0:0:0:0:1`) — peers do not spell their own address two ways
|
|
34
|
+
* within one deployment, and a full expander is more surface than the bucket
|
|
35
|
+
* key warrants.
|
|
36
|
+
*/
|
|
37
|
+
/** Longest accepted candidate. A full IPv6 + zone fits well inside this. */
|
|
38
|
+
export declare const IP_BUCKET_KEY_MAX_LENGTH = 64;
|
|
39
|
+
/**
|
|
40
|
+
* Normalize one IP candidate to its canonical bucket key, or `null` when the
|
|
41
|
+
* value is not a usable address.
|
|
42
|
+
*/
|
|
43
|
+
export declare function normalizeIpForBucketKey(value: string): string | null;
|
|
44
|
+
//# sourceMappingURL=ip-normalize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ip-normalize.d.ts","sourceRoot":"","sources":["../../src/chat-protocol/ip-normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,4EAA4E;AAC5E,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAqD1C;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkDpE"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NATS chunk → normalized `ChatStreamEvent` decoder.
|
|
3
|
+
*
|
|
4
|
+
* THE live NATS reading path — the ONLY chunk parser in the codebase. Every
|
|
5
|
+
* consumer (this lib's `useNatsChatAdapter`, the hub, the product app) feeds
|
|
6
|
+
* raw chunks through `decodeNatsChunk` into `createChatStreamReducer`. The
|
|
7
|
+
* legacy `components/chat/utils/chunk-parser.ts` (`parseChunkToAction`) that
|
|
8
|
+
* this module superseded was DELETED — do not reintroduce a second decoder.
|
|
9
|
+
*
|
|
10
|
+
* Chunks map onto the transport-agnostic event union, with the JetStream
|
|
11
|
+
* `streamSeq` lifted into the `seq` envelope (the reducer's idempotency gate
|
|
12
|
+
* keys off it).
|
|
13
|
+
*
|
|
14
|
+
* Behavior is pinned by `__tests__/nats-decoder-golden.test.ts`.
|
|
15
|
+
*
|
|
16
|
+
* Server-safe: no React, no browser APIs.
|
|
17
|
+
*/
|
|
18
|
+
import type { ChatStreamEvent } from './events';
|
|
19
|
+
/**
|
|
20
|
+
* Parse one raw NATS chunk into a normalized event. Returns `null` for
|
|
21
|
+
* unknown/malformed chunks — an unrecognized `type`, a missing required
|
|
22
|
+
* field, or a non-object payload are all tolerated as no-ops rather than
|
|
23
|
+
* throwing, so a backend that adds a chunk type can't break the stream.
|
|
24
|
+
*/
|
|
25
|
+
export declare function decodeNatsChunk(chunk: unknown): ChatStreamEvent | null;
|
|
26
|
+
//# sourceMappingURL=nats-decoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nats-decoder.d.ts","sourceRoot":"","sources":["../../src/chat-protocol/nats-decoder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAoB,eAAe,EAAE,MAAM,UAAU,CAAA;AA4BjE;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,GAAG,IAAI,CAsMtE"}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
PageLayout,
|
|
4
4
|
formatBioText,
|
|
5
5
|
getProxiedImageUrl
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-BE6DK7QY.js";
|
|
7
7
|
import {
|
|
8
8
|
useChatRuntime
|
|
9
9
|
} from "./chunk-6GT557KN.js";
|
|
@@ -146,4 +146,4 @@ export {
|
|
|
146
146
|
DetailPageSkeleton,
|
|
147
147
|
ArticleAuthorByline
|
|
148
148
|
};
|
|
149
|
-
//# sourceMappingURL=chunk-
|
|
149
|
+
//# sourceMappingURL=chunk-4NWARV5I.js.map
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
var
|
|
6
|
+
var _chunkQSCHCZL3cjs = require('./chunk-QSCHCZL3.cjs');
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var _chunk5EYRXSY5cjs = require('./chunk-5EYRXSY5.cjs');
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
@@ -19,7 +19,7 @@ var _chunkH3YRJ3LZcjs = require('./chunk-H3YRJ3LZ.cjs');
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
var
|
|
22
|
+
var _chunk5LMGFI4Jcjs = require('./chunk-5LMGFI4J.cjs');
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
|
|
@@ -1065,8 +1065,8 @@ function findFirstDocPath(folder) {
|
|
|
1065
1065
|
}
|
|
1066
1066
|
function useDocumentTree(config, initialPath) {
|
|
1067
1067
|
const { structureEndpoint, contentEndpoint, baseRoute } = config;
|
|
1068
|
-
const folderIndexFile = _nullishCoalesce(config.folderIndexFile, () => (
|
|
1069
|
-
const cleanInitialPath =
|
|
1068
|
+
const folderIndexFile = _nullishCoalesce(config.folderIndexFile, () => ( _chunk5LMGFI4Jcjs.DEFAULT_FOLDER_INDEX_FILE));
|
|
1069
|
+
const cleanInitialPath = _chunk5LMGFI4Jcjs.stripFolderIndexFromPath.call(void 0,
|
|
1070
1070
|
_optionalChain([initialPath, 'optionalAccess', _2 => _2.replace, 'call', _3 => _3(/\/$/, "")]) || "",
|
|
1071
1071
|
folderIndexFile
|
|
1072
1072
|
);
|
|
@@ -1092,12 +1092,12 @@ function useDocumentTree(config, initialPath) {
|
|
|
1092
1092
|
} else if (pathname.startsWith(`${normalizedBaseRoute}/`)) {
|
|
1093
1093
|
pathFromUrl = pathname.substring(`${normalizedBaseRoute}/`.length);
|
|
1094
1094
|
}
|
|
1095
|
-
pathFromUrl =
|
|
1095
|
+
pathFromUrl = _chunk5LMGFI4Jcjs.stripFolderIndexFromPath.call(void 0, pathFromUrl, folderIndexFile);
|
|
1096
1096
|
if (pathFromUrl !== selectedPathRef.current) {
|
|
1097
1097
|
setSelectedPath(pathFromUrl);
|
|
1098
1098
|
if (pathFromUrl) {
|
|
1099
1099
|
const parentPath = pathFromUrl.includes("/") ? pathFromUrl.substring(0, pathFromUrl.lastIndexOf("/")) : pathFromUrl;
|
|
1100
|
-
setExpandedNodes(new Set(
|
|
1100
|
+
setExpandedNodes(new Set(_chunk5LMGFI4Jcjs.getDocAncestorNodeIds.call(void 0, parentPath)));
|
|
1101
1101
|
}
|
|
1102
1102
|
setTimeout(() => {
|
|
1103
1103
|
scrollToContent();
|
|
@@ -1112,7 +1112,7 @@ function useDocumentTree(config, initialPath) {
|
|
|
1112
1112
|
setSelectedPath(cleanInitialPath);
|
|
1113
1113
|
if (cleanInitialPath) {
|
|
1114
1114
|
const parentPath = cleanInitialPath.includes("/") ? cleanInitialPath.substring(0, cleanInitialPath.lastIndexOf("/")) : cleanInitialPath;
|
|
1115
|
-
setExpandedNodes(new Set(
|
|
1115
|
+
setExpandedNodes(new Set(_chunk5LMGFI4Jcjs.getDocAncestorNodeIds.call(void 0, parentPath)));
|
|
1116
1116
|
}
|
|
1117
1117
|
setTimeout(scrollToContent, 150);
|
|
1118
1118
|
}, [cleanInitialPath]);
|
|
@@ -1132,7 +1132,7 @@ function useDocumentTree(config, initialPath) {
|
|
|
1132
1132
|
if (selectedPath === "") {
|
|
1133
1133
|
pathToFetch = folderIndexFile;
|
|
1134
1134
|
} else {
|
|
1135
|
-
const node =
|
|
1135
|
+
const node = _chunk5LMGFI4Jcjs.findDocNodeByPath.call(void 0, selectedPath, structure);
|
|
1136
1136
|
if (node && node.type === "folder" && !node.hasReadme) {
|
|
1137
1137
|
const firstDocPath = findFirstDocPath(node);
|
|
1138
1138
|
if (!firstDocPath) {
|
|
@@ -1174,7 +1174,7 @@ function useDocumentTree(config, initialPath) {
|
|
|
1174
1174
|
if (cleanInitialPath) {
|
|
1175
1175
|
const pathForExpansion = cleanInitialPath.includes(".") ? cleanInitialPath.substring(0, cleanInitialPath.lastIndexOf("/")) : cleanInitialPath;
|
|
1176
1176
|
if (pathForExpansion) {
|
|
1177
|
-
setExpandedNodes(new Set(
|
|
1177
|
+
setExpandedNodes(new Set(_chunk5LMGFI4Jcjs.getDocAncestorNodeIds.call(void 0, pathForExpansion)));
|
|
1178
1178
|
}
|
|
1179
1179
|
} else if (result.data.length > 0) {
|
|
1180
1180
|
const hasRootReadme = result.data.some(
|
|
@@ -1216,8 +1216,8 @@ function useDocumentTree(config, initialPath) {
|
|
|
1216
1216
|
setContent(null);
|
|
1217
1217
|
return;
|
|
1218
1218
|
}
|
|
1219
|
-
const probe =
|
|
1220
|
-
|
|
1219
|
+
const probe = _chunk5LMGFI4Jcjs.findDocNodeByPath.call(void 0,
|
|
1220
|
+
_chunk5LMGFI4Jcjs.stripFolderIndexFromPath.call(void 0, path, folderIndexFile),
|
|
1221
1221
|
structure
|
|
1222
1222
|
);
|
|
1223
1223
|
const probeIsNoReadmeFolder = !!probe && probe.type === "folder" && !probe.hasReadme;
|
|
@@ -1274,16 +1274,16 @@ function useDocumentTree(config, initialPath) {
|
|
|
1274
1274
|
if (node.type === "folder") {
|
|
1275
1275
|
setExpandedNodes((prev) => {
|
|
1276
1276
|
if (prev.has(node.id)) {
|
|
1277
|
-
const ancestorIds =
|
|
1277
|
+
const ancestorIds = _chunk5LMGFI4Jcjs.getDocAncestorNodeIds.call(void 0, node.path);
|
|
1278
1278
|
ancestorIds.pop();
|
|
1279
1279
|
return new Set(ancestorIds);
|
|
1280
1280
|
}
|
|
1281
|
-
return new Set(
|
|
1281
|
+
return new Set(_chunk5LMGFI4Jcjs.getDocAncestorNodeIds.call(void 0, node.path));
|
|
1282
1282
|
});
|
|
1283
1283
|
} else {
|
|
1284
1284
|
const lastSlash = node.path.lastIndexOf("/");
|
|
1285
1285
|
if (lastSlash > 0) {
|
|
1286
|
-
setExpandedNodes(new Set(
|
|
1286
|
+
setExpandedNodes(new Set(_chunk5LMGFI4Jcjs.getDocAncestorNodeIds.call(void 0, node.path.substring(0, lastSlash))));
|
|
1287
1287
|
}
|
|
1288
1288
|
}
|
|
1289
1289
|
lastFetchedPath.current = null;
|
|
@@ -1295,7 +1295,7 @@ function useDocumentTree(config, initialPath) {
|
|
|
1295
1295
|
const hashIndex = path.indexOf("#");
|
|
1296
1296
|
const anchor = hashIndex !== -1 ? path.substring(hashIndex) : "";
|
|
1297
1297
|
const cleanPath = path.replace(/\/$/, "").split("#")[0];
|
|
1298
|
-
const pathForSelection = anchor && _optionalChain([options, 'optionalAccess', _4 => _4.fromInternalLink]) && cleanPath === "" ? selectedPathRef.current :
|
|
1298
|
+
const pathForSelection = anchor && _optionalChain([options, 'optionalAccess', _4 => _4.fromInternalLink]) && cleanPath === "" ? selectedPathRef.current : _chunk5LMGFI4Jcjs.stripFolderIndexFromPath.call(void 0, cleanPath, folderIndexFile);
|
|
1299
1299
|
if (anchor && _optionalChain([options, 'optionalAccess', _5 => _5.fromInternalLink]) && pathForSelection === selectedPathRef.current) {
|
|
1300
1300
|
_chunkBIKOJ4FHcjs.navigateSamePageHash.call(void 0, anchor, { headerOffset: _chunkBIKOJ4FHcjs.HUB_HEADER_OFFSET_PX });
|
|
1301
1301
|
return;
|
|
@@ -1357,8 +1357,8 @@ function useDocumentTree(config, initialPath) {
|
|
|
1357
1357
|
return docNavigation.register({
|
|
1358
1358
|
baseRoute: normalizedBaseRoute,
|
|
1359
1359
|
findNodeByPath: (path) => {
|
|
1360
|
-
const clean =
|
|
1361
|
-
return _nullishCoalesce(
|
|
1360
|
+
const clean = _chunk5LMGFI4Jcjs.stripFolderIndexFromPath.call(void 0, path.replace(/\/$/, "").split("#")[0], folderIndexFile);
|
|
1361
|
+
return _nullishCoalesce(_chunk5LMGFI4Jcjs.findDocNodeByPath.call(void 0, clean, structure), () => ( null));
|
|
1362
1362
|
},
|
|
1363
1363
|
selectNode
|
|
1364
1364
|
});
|
|
@@ -1531,7 +1531,7 @@ function DocViewerContent({
|
|
|
1531
1531
|
label: _nullishCoalesce(_optionalChain([backButton, 'optionalAccess', _23 => _23.label]), () => ( "Back to home")),
|
|
1532
1532
|
onClick: () => router.push(_nullishCoalesce(_optionalChain([backButton, 'optionalAccess', _24 => _24.href]), () => ( "/")))
|
|
1533
1533
|
};
|
|
1534
|
-
const docSearch =
|
|
1534
|
+
const docSearch = _chunk5EYRXSY5cjs.useDocSearch.call(void 0, {
|
|
1535
1535
|
source: chatSource,
|
|
1536
1536
|
baseRoute,
|
|
1537
1537
|
searchEndpoint,
|
|
@@ -1555,7 +1555,7 @@ function DocViewerContent({
|
|
|
1555
1555
|
onResolveLink: resolveLink
|
|
1556
1556
|
});
|
|
1557
1557
|
}, [content, renderContent, navigateToDoc, sourceId, resolveLink]);
|
|
1558
|
-
const selectedNodeDocType = selectedPath && structure.length > 0 ? _optionalChain([
|
|
1558
|
+
const selectedNodeDocType = selectedPath && structure.length > 0 ? _optionalChain([_chunk5LMGFI4Jcjs.findDocNodeByPath.call(void 0, selectedPath, structure), 'optionalAccess', _25 => _25.documentType]) : void 0;
|
|
1559
1559
|
const activeDocType = _nullishCoalesce(_optionalChain([content, 'optionalAccess', _26 => _26.documentType]), () => ( selectedNodeDocType));
|
|
1560
1560
|
const isMarkdownContent = !activeDocType || activeDocType === "markdown";
|
|
1561
1561
|
const showStickyNav = isMarkdownContent;
|
|
@@ -1566,9 +1566,9 @@ function DocViewerContent({
|
|
|
1566
1566
|
const containerBgStyle = colorPalette.containerBackground !== "transparent" ? { backgroundColor: colorPalette.containerBackground } : {};
|
|
1567
1567
|
const defaultEmptyText = structure.length > 0 ? "Select a document from the sidebar to view" : "No documents yet. Add content from the admin panel.";
|
|
1568
1568
|
const resolvedEmptyText = emptyStateText || defaultEmptyText;
|
|
1569
|
-
const inner = /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: { ...bgStyle, ...containerBgStyle }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1569
|
+
const inner = /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { style: { ...bgStyle, ...containerBgStyle }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5LMGFI4Jcjs.PageLayout, { title, subtitle, titleSize: "h1", titleWrap: true, backButton: _nullishCoalesce(backCfg, () => ( void 0)), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "w-full flex flex-col gap-10", children: [
|
|
1570
1570
|
showAIChat && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1571
|
-
|
|
1571
|
+
_chunk5EYRXSY5cjs.DocSearchBar,
|
|
1572
1572
|
{
|
|
1573
1573
|
placeholder: `Search ${_optionalChain([sidebarLabel, 'optionalAccess', _30 => _30.toLowerCase, 'call', _31 => _31()]) || "documents"}...`,
|
|
1574
1574
|
query: docSearch.query,
|
|
@@ -1589,7 +1589,7 @@ function DocViewerContent({
|
|
|
1589
1589
|
!error && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col lg:flex-row gap-6 lg:gap-10 items-start flex-1", children: [
|
|
1590
1590
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full lg:w-[320px] lg:shrink-0", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "lg:sticky lg:top-20", children: isLoadingStructure ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CategorySidebarSkeleton, {}) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
1591
1591
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, PersistentMobileDropdown, { isLoading: false, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1592
|
-
|
|
1592
|
+
_chunk5LMGFI4Jcjs.MobileNavigationDropdown,
|
|
1593
1593
|
{
|
|
1594
1594
|
nodes: structure,
|
|
1595
1595
|
selectedPath,
|
|
@@ -1603,7 +1603,7 @@ function DocViewerContent({
|
|
|
1603
1603
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, PersistentSidebar, { isLoading: false, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "hidden lg:block", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "space-y-4", children: [
|
|
1604
1604
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "text-h5 font-semibold text-ods-text-secondary", children: sidebarLabel }),
|
|
1605
1605
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1606
|
-
|
|
1606
|
+
_chunk5LMGFI4Jcjs.MultiLevelNavigation,
|
|
1607
1607
|
{
|
|
1608
1608
|
nodes: structure,
|
|
1609
1609
|
selectedPath,
|
|
@@ -1648,7 +1648,7 @@ function DocViewerContent({
|
|
|
1648
1648
|
showStickyNav && content && stickyNavSections.length > 0 && !isLoadingContent && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "hidden lg:block", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "sticky top-24", children: [
|
|
1649
1649
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "text-h5 font-semibold text-ods-text-secondary mb-4", children: "ON THIS PAGE" }),
|
|
1650
1650
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1651
|
-
|
|
1651
|
+
_chunk5LMGFI4Jcjs.StickySectionNav,
|
|
1652
1652
|
{
|
|
1653
1653
|
sections: stickyNavSections,
|
|
1654
1654
|
activeSection,
|
|
@@ -1663,7 +1663,7 @@ function DocViewerContent({
|
|
|
1663
1663
|
) })
|
|
1664
1664
|
] })
|
|
1665
1665
|
] }) }) });
|
|
1666
|
-
return shell ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1666
|
+
return shell ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5LMGFI4Jcjs.PageShell, { contentClassName: `${bgClass} ${className}`, children: inner }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: `page-shell-content ${bgClass} ${className}`.trim(), children: inner });
|
|
1667
1667
|
}
|
|
1668
1668
|
|
|
1669
1669
|
// src/components/docs/skeletons.tsx
|
|
@@ -1759,11 +1759,11 @@ function EmbedSkeleton({ documentType } = {}) {
|
|
|
1759
1759
|
|
|
1760
1760
|
var DEFAULT_TITLE = "Documents";
|
|
1761
1761
|
var defaultFallbackRenderer = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "text-center py-16", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary", children: "Unsupported document type" }) });
|
|
1762
|
-
var defaultPdfRenderer = (content, handlers) => content.fileUrl ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1763
|
-
var defaultGoogleSheetRenderer = (content, handlers) => content.externalUrl ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1764
|
-
var defaultFigmaRenderer = (content, handlers) => content.externalUrl ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1762
|
+
var defaultPdfRenderer = (content, handlers) => content.fileUrl ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQSCHCZL3cjs.PdfViewer, { src: content.fileUrl, fileName: content.fileName }) : defaultFallbackRenderer(content, handlers);
|
|
1763
|
+
var defaultGoogleSheetRenderer = (content, handlers) => content.externalUrl ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQSCHCZL3cjs.GoogleSheetsViewer, { externalUrl: content.externalUrl, fileName: content.fileName }) : defaultFallbackRenderer(content, handlers);
|
|
1764
|
+
var defaultFigmaRenderer = (content, handlers) => content.externalUrl ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk5LMGFI4Jcjs.FigmaEmbed, { url: content.externalUrl, title: content.fileName, loading: "eager" }) : defaultFallbackRenderer(content, handlers);
|
|
1765
1765
|
var defaultFileRenderer = (content) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
1766
|
-
|
|
1766
|
+
_chunkQSCHCZL3cjs.FileDownloadCard,
|
|
1767
1767
|
{
|
|
1768
1768
|
fileName: content.fileName,
|
|
1769
1769
|
mimeType: content.mimeType,
|
|
@@ -1845,4 +1845,4 @@ function DocsHubPage({
|
|
|
1845
1845
|
|
|
1846
1846
|
|
|
1847
1847
|
exports.PersistentFilterControls = PersistentFilterControls; exports.PersistentSearchContainer = PersistentSearchContainer; exports.PersistentSidebar = PersistentSidebar; exports.PersistentMobileDropdown = PersistentMobileDropdown; exports.UnifiedSkeleton = UnifiedSkeleton; exports.TextSkeleton = TextSkeleton; exports.InteractiveSkeleton = InteractiveSkeleton; exports.MediaSkeleton = MediaSkeleton; exports.CardSkeleton = CardSkeleton; exports.CardSkeletonGrid = CardSkeletonGrid; exports.AnnouncementBarSkeleton = AnnouncementBarSkeleton; exports.HeroSkeleton = HeroSkeleton; exports.SearchContainerSkeleton = SearchContainerSkeleton; exports.CategorySidebarSkeleton = CategorySidebarSkeleton; exports.BreadcrumbSkeleton = BreadcrumbSkeleton; exports.ResultsHeaderSkeleton = ResultsHeaderSkeleton; exports.TwoColumnLayoutSkeleton = TwoColumnLayoutSkeleton; exports.ArticleLayoutSkeleton = ArticleLayoutSkeleton; exports.VendorDetailLayoutSkeleton = VendorDetailLayoutSkeleton; exports.StatsSectionSkeleton = StatsSectionSkeleton; exports.BlogCardGridSkeleton = BlogCardGridSkeleton; exports.VendorGridSkeleton = VendorGridSkeleton; exports.SlackCommunitySkeleton = SlackCommunitySkeleton; exports.DocNavigationProvider = DocNavigationProvider; exports.useDocNavigation = useDocNavigation; exports.useDocumentTree = useDocumentTree; exports.useScrollSpy = useScrollSpy; exports.DocViewer = DocViewer; exports.MarkdownSkeleton = MarkdownSkeleton; exports.EmbedSkeleton = EmbedSkeleton; exports.DocsHubPage = DocsHubPage;
|
|
1848
|
-
//# sourceMappingURL=chunk-
|
|
1848
|
+
//# sourceMappingURL=chunk-5CJR2GZ4.cjs.map
|