@flamingo-stack/openframe-frontend-core 0.0.554 → 0.0.555-snapshot.20260818112641
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/{chunk-P6LUXP5E.js → chunk-5756Q6UN.js} +3 -3
- package/dist/{chunk-44QNFLHC.js → chunk-5EES5HD4.js} +6 -6
- package/dist/{chunk-VIDE4YOQ.js → chunk-5JWLZJK5.js} +2 -2
- package/dist/{chunk-RMGX6BVQ.js → chunk-5M4PS3XX.js} +3 -3
- package/dist/{chunk-4KIPZULI.cjs → chunk-7Q7GFIFB.cjs} +7 -7
- package/dist/{chunk-4KIPZULI.cjs.map → chunk-7Q7GFIFB.cjs.map} +1 -1
- package/dist/{chunk-JJKK7E66.cjs → chunk-BNMKHG2L.cjs} +4 -4
- package/dist/{chunk-JJKK7E66.cjs.map → chunk-BNMKHG2L.cjs.map} +1 -1
- package/dist/{chunk-ULH6JHWZ.cjs → chunk-BZKUID4R.cjs} +14 -14
- package/dist/{chunk-ULH6JHWZ.cjs.map → chunk-BZKUID4R.cjs.map} +1 -1
- package/dist/{chunk-CWLV6DEK.cjs → chunk-C74PZU6M.cjs} +32 -32
- package/dist/{chunk-CWLV6DEK.cjs.map → chunk-C74PZU6M.cjs.map} +1 -1
- package/dist/{chunk-67Q4QQBA.js → chunk-CGUSNV6R.js} +8 -8
- package/dist/{chunk-PAW27EWH.cjs → chunk-CRGIXNUE.cjs} +23 -23
- package/dist/{chunk-PAW27EWH.cjs.map → chunk-CRGIXNUE.cjs.map} +1 -1
- package/dist/{chunk-Q6RC3YGW.cjs → chunk-DFJ7TWH6.cjs} +3 -3
- package/dist/{chunk-Q6RC3YGW.cjs.map → chunk-DFJ7TWH6.cjs.map} +1 -1
- package/dist/{chunk-5VICQQM7.js → chunk-FLSEJSTN.js} +2 -2
- package/dist/{chunk-PDVSL7OW.js → chunk-FZT7BYNF.js} +2 -2
- package/dist/{chunk-J355HL3X.cjs → chunk-HOEOGFQM.cjs} +97 -97
- package/dist/{chunk-J355HL3X.cjs.map → chunk-HOEOGFQM.cjs.map} +1 -1
- package/dist/{chunk-HO6IG73U.cjs → chunk-HYABNMBN.cjs} +76 -76
- package/dist/{chunk-HO6IG73U.cjs.map → chunk-HYABNMBN.cjs.map} +1 -1
- package/dist/{chunk-QH3QWY3N.cjs → chunk-ICG7JRYT.cjs} +40 -40
- package/dist/{chunk-QH3QWY3N.cjs.map → chunk-ICG7JRYT.cjs.map} +1 -1
- package/dist/{chunk-CGCQ4HA5.cjs → chunk-JDUPAHJR.cjs} +18 -18
- package/dist/{chunk-CGCQ4HA5.cjs.map → chunk-JDUPAHJR.cjs.map} +1 -1
- package/dist/{chunk-QA7NU73D.js → chunk-JRWOHH7K.js} +2 -2
- package/dist/{chunk-FHS2SA5F.js → chunk-JXJ4FTKN.js} +3 -3
- package/dist/{chunk-AQFYI3HH.cjs → chunk-LZD3VSPS.cjs} +12 -12
- package/dist/{chunk-AQFYI3HH.cjs.map → chunk-LZD3VSPS.cjs.map} +1 -1
- package/dist/{chunk-WZWQWZFJ.cjs → chunk-Q5SZ2QTZ.cjs} +42 -42
- package/dist/{chunk-WZWQWZFJ.cjs.map → chunk-Q5SZ2QTZ.cjs.map} +1 -1
- package/dist/{chunk-GSONSIWG.js → chunk-R7A7WHXP.js} +60 -35
- package/dist/chunk-R7A7WHXP.js.map +1 -0
- package/dist/{chunk-2HWN6CYI.cjs → chunk-S4LL6QI6.cjs} +176 -168
- package/dist/chunk-S4LL6QI6.cjs.map +1 -0
- package/dist/{chunk-KQKU4VXB.cjs → chunk-STHVHAV4.cjs} +82 -57
- package/dist/chunk-STHVHAV4.cjs.map +1 -0
- package/dist/{chunk-PFQVCHDE.cjs → chunk-SXMJLNOF.cjs} +3 -3
- package/dist/{chunk-PFQVCHDE.cjs.map → chunk-SXMJLNOF.cjs.map} +1 -1
- package/dist/{chunk-SBXQW72U.js → chunk-VF4DCOPD.js} +5 -5
- package/dist/{chunk-QTO3WYB2.cjs → chunk-VJTD2DGF.cjs} +3 -3
- package/dist/{chunk-QTO3WYB2.cjs.map → chunk-VJTD2DGF.cjs.map} +1 -1
- package/dist/{chunk-VGLDA77S.js → chunk-VRX6Y6A7.js} +2 -2
- package/dist/{chunk-U72YYXBT.js → chunk-VXNMOGRP.js} +6 -6
- package/dist/{chunk-OR67WC32.js → chunk-WBQ3NOH7.js} +2 -2
- package/dist/{chunk-DXAUNMFM.js → chunk-WX5UCLL7.js} +2 -2
- package/dist/{chunk-ZGLMZM2I.js → chunk-XGBVHQP7.js} +32 -24
- package/dist/{chunk-ZGLMZM2I.js.map → chunk-XGBVHQP7.js.map} +1 -1
- package/dist/{chunk-FVXND3SO.js → chunk-YM2WHYYK.js} +4 -4
- package/dist/{chunk-XMB5P2OS.cjs → chunk-Z3R3LOC5.cjs} +5 -5
- package/dist/{chunk-XMB5P2OS.cjs.map → chunk-Z3R3LOC5.cjs.map} +1 -1
- package/dist/components/case-studies/index.cjs +10 -10
- package/dist/components/case-studies/index.js +4 -4
- package/dist/components/chat/index.cjs +4 -4
- package/dist/components/chat/index.js +3 -3
- package/dist/components/chat/stream/chat-stream-reducer.d.ts +1 -1
- package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +1 -1
- package/dist/components/chat/utils/message-segment-accumulator.d.ts +7 -5
- package/dist/components/chat/utils/message-segment-accumulator.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +5 -5
- package/dist/components/contact/index.js +4 -4
- package/dist/components/docs/index.cjs +7 -7
- package/dist/components/docs/index.js +6 -6
- package/dist/components/embeds/index.cjs +5 -5
- package/dist/components/embeds/index.js +4 -4
- package/dist/components/faq/index.cjs +6 -6
- package/dist/components/faq/index.js +5 -5
- package/dist/components/features/index.cjs +4 -4
- package/dist/components/features/index.js +3 -3
- package/dist/components/help-center-pages/index.cjs +25 -25
- package/dist/components/help-center-pages/index.js +16 -16
- package/dist/components/index.cjs +138 -138
- package/dist/components/index.js +14 -14
- package/dist/components/meeting-scheduler/index.cjs +35 -35
- package/dist/components/meeting-scheduler/index.js +5 -5
- package/dist/components/navigation/index.cjs +4 -4
- package/dist/components/navigation/index.js +3 -3
- package/dist/components/onboarding-guides/index.cjs +8 -8
- package/dist/components/onboarding-guides/index.js +7 -7
- package/dist/components/related-content/index.cjs +6 -6
- package/dist/components/related-content/index.js +5 -5
- package/dist/components/tickets/index.cjs +8 -8
- package/dist/components/tickets/index.js +7 -7
- package/dist/components/ui/index.cjs +4 -4
- package/dist/components/ui/index.js +3 -3
- package/dist/hooks/index.cjs +3 -3
- package/dist/hooks/index.js +2 -2
- package/dist/index.cjs +4 -4
- package/dist/index.js +3 -3
- package/dist/nats/index.cjs +2 -2
- package/dist/nats/index.js +1 -1
- package/dist/nats/nats.d.ts.map +1 -1
- package/dist/nats/shared-connection.d.ts +13 -6
- package/dist/nats/shared-connection.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/chat/__tests__/ticket-event.test.ts +52 -0
- package/src/components/chat/stream/chat-stream-reducer.ts +15 -11
- package/src/components/chat/utils/message-segment-accumulator.ts +31 -17
- package/src/nats/__tests__/reconnect-lifecycle.test.tsx +814 -0
- package/src/nats/nats.ts +56 -13
- package/src/nats/shared-connection.ts +132 -36
- package/dist/chunk-2HWN6CYI.cjs.map +0 -1
- package/dist/chunk-GSONSIWG.js.map +0 -1
- package/dist/chunk-KQKU4VXB.cjs.map +0 -1
- /package/dist/{chunk-P6LUXP5E.js.map → chunk-5756Q6UN.js.map} +0 -0
- /package/dist/{chunk-44QNFLHC.js.map → chunk-5EES5HD4.js.map} +0 -0
- /package/dist/{chunk-VIDE4YOQ.js.map → chunk-5JWLZJK5.js.map} +0 -0
- /package/dist/{chunk-RMGX6BVQ.js.map → chunk-5M4PS3XX.js.map} +0 -0
- /package/dist/{chunk-67Q4QQBA.js.map → chunk-CGUSNV6R.js.map} +0 -0
- /package/dist/{chunk-5VICQQM7.js.map → chunk-FLSEJSTN.js.map} +0 -0
- /package/dist/{chunk-PDVSL7OW.js.map → chunk-FZT7BYNF.js.map} +0 -0
- /package/dist/{chunk-QA7NU73D.js.map → chunk-JRWOHH7K.js.map} +0 -0
- /package/dist/{chunk-FHS2SA5F.js.map → chunk-JXJ4FTKN.js.map} +0 -0
- /package/dist/{chunk-SBXQW72U.js.map → chunk-VF4DCOPD.js.map} +0 -0
- /package/dist/{chunk-VGLDA77S.js.map → chunk-VRX6Y6A7.js.map} +0 -0
- /package/dist/{chunk-U72YYXBT.js.map → chunk-VXNMOGRP.js.map} +0 -0
- /package/dist/{chunk-OR67WC32.js.map → chunk-WBQ3NOH7.js.map} +0 -0
- /package/dist/{chunk-DXAUNMFM.js.map → chunk-WX5UCLL7.js.map} +0 -0
- /package/dist/{chunk-FVXND3SO.js.map → chunk-YM2WHYYK.js.map} +0 -0
|
@@ -161,6 +161,58 @@ describe('accumulator — hydrate/catch-up overlap', () => {
|
|
|
161
161
|
)
|
|
162
162
|
expect(events(segments)).toHaveLength(2)
|
|
163
163
|
})
|
|
164
|
+
|
|
165
|
+
it('renders a payload-identical REPEATED event whose first occurrence is seq-less', () => {
|
|
166
|
+
// The observed swallow: resolve -> reopen -> resolve by the SAME actor
|
|
167
|
+
// with no reason. The first resolve hydrated from history without a seq,
|
|
168
|
+
// so payload equality matched it against the NEW resolve and the final
|
|
169
|
+
// card never rendered. Only the LATEST ticket event may payload-match.
|
|
170
|
+
const accumulator = new MessageSegmentAccumulator()
|
|
171
|
+
accumulator.addTicketEvent({ kind: 'RESOLVED', actorId: 'u-1', actorName: 'Yevhenii', actorType: 'TECHNICIAN' })
|
|
172
|
+
accumulator.addTicketEvent(
|
|
173
|
+
{ kind: 'REOPENED', actorId: 'u-1', actorName: 'Yevhenii', actorType: 'TECHNICIAN', targetStatusKind: 'TECH_REQUIRED' },
|
|
174
|
+
79,
|
|
175
|
+
)
|
|
176
|
+
const segments = accumulator.addTicketEvent(
|
|
177
|
+
{ kind: 'RESOLVED', actorId: 'u-1', actorName: 'Yevhenii', actorType: 'TECHNICIAN' },
|
|
178
|
+
80,
|
|
179
|
+
)
|
|
180
|
+
const rendered = events(segments)
|
|
181
|
+
expect(rendered).toHaveLength(3)
|
|
182
|
+
expect(rendered[2].data.kind).toBe('RESOLVED')
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('renders an entirely seq-less repeated cycle (no sequences anywhere)', () => {
|
|
186
|
+
const accumulator = new MessageSegmentAccumulator()
|
|
187
|
+
accumulator.addTicketEvent({ kind: 'RESOLVED', actorName: 'Fae', actorType: 'AI' })
|
|
188
|
+
accumulator.addTicketEvent({ kind: 'REOPENED', actorName: 'Fae', actorType: 'AI' })
|
|
189
|
+
const segments = accumulator.addTicketEvent({ kind: 'RESOLVED', actorName: 'Fae', actorType: 'AI' })
|
|
190
|
+
expect(events(segments)).toHaveLength(3)
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
describe('chat stream reducer — onTicketEvent effect', () => {
|
|
195
|
+
it('emits the event payload so hosts can move ticket state with the card', () => {
|
|
196
|
+
const seen: unknown[] = []
|
|
197
|
+
const reducer = createChatStreamReducer({
|
|
198
|
+
transport: 'nats',
|
|
199
|
+
onEffect: (effect) => {
|
|
200
|
+
if (effect.name === 'onTicketEvent') seen.push(effect.args[0])
|
|
201
|
+
},
|
|
202
|
+
})
|
|
203
|
+
const event = decodeNatsChunk({
|
|
204
|
+
type: 'TICKET_EVENT',
|
|
205
|
+
kind: 'REOPENED',
|
|
206
|
+
actorId: 'u-1',
|
|
207
|
+
actorName: 'Yevhenii',
|
|
208
|
+
actorType: 'TECHNICIAN',
|
|
209
|
+
targetStatusKind: 'TECH_REQUIRED',
|
|
210
|
+
streamSeq: 5,
|
|
211
|
+
})
|
|
212
|
+
if (event) reducer.apply(event)
|
|
213
|
+
expect(seen).toHaveLength(1)
|
|
214
|
+
expect(seen[0]).toMatchObject({ kind: 'REOPENED', targetStatusKind: 'TECH_REQUIRED' })
|
|
215
|
+
})
|
|
164
216
|
})
|
|
165
217
|
|
|
166
218
|
describe('processHistoricalMessages — ticket event', () => {
|
|
@@ -209,6 +209,7 @@ export interface ChatReducerEffect {
|
|
|
209
209
|
| 'onToolExecuted'
|
|
210
210
|
| 'onAgentBusy'
|
|
211
211
|
| 'onDialogClosed'
|
|
212
|
+
| 'onTicketEvent'
|
|
212
213
|
| 'segments-after-approval-result'
|
|
213
214
|
args: unknown[]
|
|
214
215
|
}
|
|
@@ -1369,18 +1370,21 @@ export function createChatStreamReducer(
|
|
|
1369
1370
|
// `ticket-escalated`. `seq` rides onto the segment: it is the event's
|
|
1370
1371
|
// dedupe identity (see `addTicketEvent`).
|
|
1371
1372
|
const before = accumulator.getSegments().length
|
|
1372
|
-
const
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
seq,
|
|
1382
|
-
)
|
|
1373
|
+
const data = {
|
|
1374
|
+
kind: event.kind,
|
|
1375
|
+
actorId: event.actorId,
|
|
1376
|
+
actorName: event.actorName,
|
|
1377
|
+
actorType: event.actorType,
|
|
1378
|
+
reason: event.reason,
|
|
1379
|
+
targetStatusKind: event.targetStatusKind,
|
|
1380
|
+
}
|
|
1381
|
+
const segments = accumulator.addTicketEvent(data, seq)
|
|
1383
1382
|
applyAccumulated(before, segments)
|
|
1383
|
+
// The card alone is not enough for a host that also tracks the
|
|
1384
|
+
// ticket's state: a RESOLVED/REOPENED arriving live must move the
|
|
1385
|
+
// composer lock/status chip on the same render as the card, not on
|
|
1386
|
+
// the next status poll. Hosts that don't wire it lose nothing.
|
|
1387
|
+
emit('onTicketEvent', data)
|
|
1384
1388
|
break
|
|
1385
1389
|
}
|
|
1386
1390
|
|
|
@@ -540,13 +540,15 @@ export class MessageSegmentAccumulator {
|
|
|
540
540
|
/**
|
|
541
541
|
* Add a ticket lifecycle receipt (resolved / reopened / unknown kind).
|
|
542
542
|
*
|
|
543
|
-
* Upsert identity is the chunk's stream sequence when BOTH sides know it
|
|
544
|
-
*
|
|
543
|
+
* Upsert identity is the chunk's stream sequence when BOTH sides know it.
|
|
544
|
+
* The payload fallback exists for one overlap only: history hydration is
|
|
545
545
|
* seq-less (the persisted row's seq lives on the message, not the
|
|
546
546
|
* `messageData`), so a JetStream catch-up redelivery of the same event must
|
|
547
|
-
* still match its hydrated twin
|
|
548
|
-
*
|
|
549
|
-
*
|
|
547
|
+
* still match its hydrated twin. That twin is necessarily the LATEST ticket
|
|
548
|
+
* event, so the fallback may consider only that one — scanning older
|
|
549
|
+
* segments swallowed a genuinely REPEATED event: resolve → reopen → resolve
|
|
550
|
+
* by the same actor is payload-identical to the first resolve, and matching
|
|
551
|
+
* the old card meant the final one never rendered.
|
|
550
552
|
*/
|
|
551
553
|
addTicketEvent(data: TicketEventData, streamSeq?: number): MessageSegment[] {
|
|
552
554
|
const segment: TicketEventSegment = {
|
|
@@ -554,18 +556,30 @@ export class MessageSegmentAccumulator {
|
|
|
554
556
|
data,
|
|
555
557
|
...(streamSeq !== undefined ? { streamSeq } : {}),
|
|
556
558
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
s
|
|
564
|
-
s.
|
|
565
|
-
|
|
566
|
-
s.
|
|
567
|
-
|
|
568
|
-
|
|
559
|
+
let existingIndex =
|
|
560
|
+
streamSeq !== undefined
|
|
561
|
+
? this.segments.findIndex((s) => s.type === 'ticket_event' && s.streamSeq === streamSeq)
|
|
562
|
+
: -1
|
|
563
|
+
if (existingIndex === -1) {
|
|
564
|
+
for (let i = this.segments.length - 1; i >= 0; i--) {
|
|
565
|
+
const s = this.segments[i]
|
|
566
|
+
if (s.type !== 'ticket_event') continue
|
|
567
|
+
// Both seqs known and unequal: proven distinct, never payload-match.
|
|
568
|
+
const seqsDistinguish = s.streamSeq !== undefined && streamSeq !== undefined
|
|
569
|
+
if (
|
|
570
|
+
!seqsDistinguish &&
|
|
571
|
+
s.data.kind === data.kind &&
|
|
572
|
+
s.data.actorId === data.actorId &&
|
|
573
|
+
s.data.actorName === data.actorName &&
|
|
574
|
+
s.data.actorType === data.actorType &&
|
|
575
|
+
s.data.reason === data.reason &&
|
|
576
|
+
s.data.targetStatusKind === data.targetStatusKind
|
|
577
|
+
) {
|
|
578
|
+
existingIndex = i
|
|
579
|
+
}
|
|
580
|
+
break
|
|
581
|
+
}
|
|
582
|
+
}
|
|
569
583
|
if (existingIndex !== -1) {
|
|
570
584
|
this.segments[existingIndex] = segment
|
|
571
585
|
return this.getSegments()
|