@flamingo-stack/openframe-frontend-core 0.0.564-snapshot.20260824155539 → 0.0.564
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/index.cjs.map +1 -1
- package/dist/chat-protocol/index.js.map +1 -1
- package/dist/{chunk-7FH6MZ6M.cjs → chunk-6OPEULTD.cjs} +9 -9
- package/dist/{chunk-7FH6MZ6M.cjs.map → chunk-6OPEULTD.cjs.map} +1 -1
- package/dist/{chunk-5MVE77D5.js → chunk-7D62XVHH.js} +6 -6
- package/dist/{chunk-6F47STCR.js → chunk-ASULU3T2.js} +2 -2
- package/dist/{chunk-26LZFWY6.cjs → chunk-AZPUAPXW.cjs} +17 -25
- package/dist/chunk-AZPUAPXW.cjs.map +1 -0
- package/dist/{chunk-5JYX2GOP.js → chunk-BK7V6CH5.js} +17 -25
- package/dist/chunk-BK7V6CH5.js.map +1 -0
- package/dist/{chunk-7IR5LKYC.js → chunk-CP7TMQBH.js} +2 -2
- package/dist/{chunk-TXLUKQBI.js → chunk-CQNK6RS6.js} +2 -2
- package/dist/{chunk-HJ7OVIR7.js → chunk-DPMOEYEM.js} +2 -2
- package/dist/{chunk-CCFBL7JU.cjs → chunk-E6PW7GRQ.cjs} +62 -62
- package/dist/{chunk-CCFBL7JU.cjs.map → chunk-E6PW7GRQ.cjs.map} +1 -1
- package/dist/{chunk-AN7YK35P.cjs → chunk-FG4BSJ4A.cjs} +26 -26
- package/dist/{chunk-AN7YK35P.cjs.map → chunk-FG4BSJ4A.cjs.map} +1 -1
- package/dist/{chunk-DEYRHTLD.js → chunk-G2VDS3M5.js} +2 -2
- package/dist/{chunk-NCJUIT3Q.cjs → chunk-GEC2NHQH.cjs} +20 -20
- package/dist/{chunk-NCJUIT3Q.cjs.map → chunk-GEC2NHQH.cjs.map} +1 -1
- package/dist/{chunk-HWQ5HMJN.cjs → chunk-J7R3VZL5.cjs} +14 -14
- package/dist/{chunk-HWQ5HMJN.cjs.map → chunk-J7R3VZL5.cjs.map} +1 -1
- package/dist/{chunk-5K3F5AZX.js → chunk-NQ6UF4LP.js} +4 -4
- package/dist/{chunk-GCMASPSW.js → chunk-NUKQWLOG.js} +5 -5
- package/dist/{chunk-3FBPPKV2.js → chunk-O3SEC45L.js} +4 -4
- package/dist/{chunk-HVS56KQE.cjs → chunk-OYFXHET4.cjs} +7 -7
- package/dist/{chunk-HVS56KQE.cjs.map → chunk-OYFXHET4.cjs.map} +1 -1
- package/dist/{chunk-LOLVMAT3.cjs → chunk-PKCZL56Y.cjs} +4 -4
- package/dist/{chunk-LOLVMAT3.cjs.map → chunk-PKCZL56Y.cjs.map} +1 -1
- package/dist/{chunk-ISK6LRRY.cjs → chunk-PT4GS4CE.cjs} +3 -3
- package/dist/{chunk-ISK6LRRY.cjs.map → chunk-PT4GS4CE.cjs.map} +1 -1
- package/dist/{chunk-6RILRC7X.js → chunk-T3P56JKN.js} +2 -2
- package/dist/{chunk-MIBKEMZY.js → chunk-TDYF6Q2D.js} +2 -2
- package/dist/{chunk-32QBTN5L.cjs → chunk-U5EVZLL5.cjs} +5 -5
- package/dist/{chunk-32QBTN5L.cjs.map → chunk-U5EVZLL5.cjs.map} +1 -1
- package/dist/{chunk-TGT3JHVU.cjs → chunk-VVDLVCPW.cjs} +39 -39
- package/dist/{chunk-TGT3JHVU.cjs.map → chunk-VVDLVCPW.cjs.map} +1 -1
- package/dist/{chunk-TFEL2C6I.cjs → chunk-WGDZW237.cjs} +86 -86
- package/dist/{chunk-TFEL2C6I.cjs.map → chunk-WGDZW237.cjs.map} +1 -1
- package/dist/{chunk-QQFUJ6MS.js → chunk-X4JKXYY5.js} +2 -2
- package/dist/{chunk-NM5NBMMD.cjs → chunk-XFI5PCER.cjs} +31 -31
- package/dist/{chunk-NM5NBMMD.cjs.map → chunk-XFI5PCER.cjs.map} +1 -1
- package/dist/{chunk-TFRJ7B4X.cjs → chunk-YFLSOYX4.cjs} +11 -11
- package/dist/{chunk-TFRJ7B4X.cjs.map → chunk-YFLSOYX4.cjs.map} +1 -1
- package/dist/{chunk-UK6SSMUR.js → chunk-Z4VU6MJ4.js} +2 -2
- 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/index.cjs +2 -2
- package/dist/components/chat/index.js +1 -1
- package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +1 -1
- package/dist/components/chat/types/message.types.d.ts +0 -8
- package/dist/components/chat/types/message.types.d.ts.map +1 -1
- package/dist/components/chat/utils/message-segment-accumulator.d.ts +1 -1
- package/dist/components/chat/utils/message-segment-accumulator.d.ts.map +1 -1
- 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 +22 -22
- package/dist/components/help-center-pages/index.js +13 -13
- package/dist/components/index.cjs +131 -131
- package/dist/components/index.js +11 -11
- package/dist/components/meeting-scheduler/index.cjs +30 -30
- package/dist/components/meeting-scheduler/index.js +3 -3
- 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/related-content/index.cjs +3 -3
- package/dist/components/related-content/index.js +2 -2
- package/dist/components/tickets/index.cjs +6 -6
- package/dist/components/tickets/index.js +5 -5
- package/dist/components/ui/index.cjs +2 -2
- package/dist/components/ui/index.js +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.js +1 -1
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/chat/__tests__/ticket-event.test.ts +0 -86
- package/src/components/chat/chat-message-enhanced.tsx +1 -3
- package/src/components/chat/stream/chat-stream-reducer.ts +1 -7
- package/src/components/chat/types/message.types.ts +0 -8
- package/src/components/chat/utils/message-segment-accumulator.ts +3 -10
- package/src/components/chat/utils/process-historical-messages.ts +8 -17
- package/dist/chunk-26LZFWY6.cjs.map +0 -1
- package/dist/chunk-5JYX2GOP.js.map +0 -1
- /package/dist/{chunk-5MVE77D5.js.map → chunk-7D62XVHH.js.map} +0 -0
- /package/dist/{chunk-6F47STCR.js.map → chunk-ASULU3T2.js.map} +0 -0
- /package/dist/{chunk-7IR5LKYC.js.map → chunk-CP7TMQBH.js.map} +0 -0
- /package/dist/{chunk-TXLUKQBI.js.map → chunk-CQNK6RS6.js.map} +0 -0
- /package/dist/{chunk-HJ7OVIR7.js.map → chunk-DPMOEYEM.js.map} +0 -0
- /package/dist/{chunk-DEYRHTLD.js.map → chunk-G2VDS3M5.js.map} +0 -0
- /package/dist/{chunk-5K3F5AZX.js.map → chunk-NQ6UF4LP.js.map} +0 -0
- /package/dist/{chunk-GCMASPSW.js.map → chunk-NUKQWLOG.js.map} +0 -0
- /package/dist/{chunk-3FBPPKV2.js.map → chunk-O3SEC45L.js.map} +0 -0
- /package/dist/{chunk-6RILRC7X.js.map → chunk-T3P56JKN.js.map} +0 -0
- /package/dist/{chunk-MIBKEMZY.js.map → chunk-TDYF6Q2D.js.map} +0 -0
- /package/dist/{chunk-QQFUJ6MS.js.map → chunk-X4JKXYY5.js.map} +0 -0
- /package/dist/{chunk-UK6SSMUR.js.map → chunk-Z4VU6MJ4.js.map} +0 -0
package/package.json
CHANGED
|
@@ -134,21 +134,6 @@ describe('chat stream reducer — ticket event', () => {
|
|
|
134
134
|
])
|
|
135
135
|
expect(events(trailingSegments(reducer))).toHaveLength(3)
|
|
136
136
|
})
|
|
137
|
-
|
|
138
|
-
it('stamps a live card with its arrival time, not the bubble timestamp', () => {
|
|
139
|
-
// The chunk carries no event time, so arrival IS the event time for a
|
|
140
|
-
// genuinely live receipt. Without the stamp the card renders the trailing
|
|
141
|
-
// bubble's timestamp — the turn's FIRST row, minutes stale by the time a
|
|
142
|
-
// resolve/reopen lands.
|
|
143
|
-
const reducer = createChatStreamReducer({ transport: 'nats' })
|
|
144
|
-
const before = Date.now()
|
|
145
|
-
feed(reducer, [resolvedChunk(1)])
|
|
146
|
-
const after = Date.now()
|
|
147
|
-
const [card] = events(trailingSegments(reducer))
|
|
148
|
-
expect(card.occurredAt).toBeInstanceOf(Date)
|
|
149
|
-
expect(card.occurredAt!.getTime()).toBeGreaterThanOrEqual(before)
|
|
150
|
-
expect(card.occurredAt!.getTime()).toBeLessThanOrEqual(after)
|
|
151
|
-
})
|
|
152
137
|
})
|
|
153
138
|
|
|
154
139
|
describe('accumulator — hydrate/catch-up overlap', () => {
|
|
@@ -277,75 +262,4 @@ describe('processHistoricalMessages — ticket event', () => {
|
|
|
277
262
|
])
|
|
278
263
|
expect(messages.flatMap((m) => events(m.content))).toHaveLength(0)
|
|
279
264
|
})
|
|
280
|
-
|
|
281
|
-
it('stamps each card with its OWN row time, not the bubble timestamp', () => {
|
|
282
|
-
// The reported bug: resolve/reopen rows grouped into one assistant bubble
|
|
283
|
-
// all rendered the bubble's timestamp — the FIRST row of the turn (the
|
|
284
|
-
// ticket-creation-era greeting), so every lifecycle card read the same
|
|
285
|
-
// stale time.
|
|
286
|
-
const rowAt = (id: string, createdAt: string, data: Record<string, unknown>): HistoricalMessage => ({
|
|
287
|
-
id,
|
|
288
|
-
createdAt,
|
|
289
|
-
owner: { type: 'ASSISTANT' },
|
|
290
|
-
messageData: [data as never],
|
|
291
|
-
})
|
|
292
|
-
const { messages } = processHistoricalMessages([
|
|
293
|
-
rowAt('m1', '2026-08-20T13:54:00Z', { type: 'TEXT', text: 'Hi! How can I help?' }),
|
|
294
|
-
rowAt('m2', '2026-08-20T14:10:00Z', { type: 'TICKET_EVENT', kind: 'RESOLVED', actorType: 'AI' }),
|
|
295
|
-
rowAt('m3', '2026-08-20T14:33:00Z', {
|
|
296
|
-
type: 'TICKET_EVENT',
|
|
297
|
-
kind: 'REOPENED',
|
|
298
|
-
actorType: 'CLIENT',
|
|
299
|
-
targetStatusKind: 'AI_ASSISTANCE',
|
|
300
|
-
}),
|
|
301
|
-
])
|
|
302
|
-
expect(messages).toHaveLength(1)
|
|
303
|
-
// The bubble keeps the first row's time…
|
|
304
|
-
expect(messages[0].timestamp).toEqual(new Date('2026-08-20T13:54:00Z'))
|
|
305
|
-
// …but each card carries the time of its own event.
|
|
306
|
-
const cards = events(messages[0].content)
|
|
307
|
-
expect(cards.map((c) => c.occurredAt)).toEqual([
|
|
308
|
-
new Date('2026-08-20T14:10:00Z'),
|
|
309
|
-
new Date('2026-08-20T14:33:00Z'),
|
|
310
|
-
])
|
|
311
|
-
})
|
|
312
|
-
})
|
|
313
|
-
|
|
314
|
-
describe('accumulator — occurredAt across the hydrate/catch-up overlap', () => {
|
|
315
|
-
it('keeps the hydrated row time when the seq-stamped redelivery carries none', () => {
|
|
316
|
-
const accumulator = new MessageSegmentAccumulator()
|
|
317
|
-
accumulator.addTicketEvent(
|
|
318
|
-
{ kind: 'RESOLVED', actorId: 'fae', actorName: 'Fae', actorType: 'AI' },
|
|
319
|
-
undefined,
|
|
320
|
-
new Date('2026-08-20T14:10:00Z'),
|
|
321
|
-
)
|
|
322
|
-
// Same event redelivered live (JetStream catch-up): seq known, time not.
|
|
323
|
-
const segments = accumulator.addTicketEvent(
|
|
324
|
-
{ kind: 'RESOLVED', actorId: 'fae', actorName: 'Fae', actorType: 'AI' },
|
|
325
|
-
412,
|
|
326
|
-
)
|
|
327
|
-
const rendered = events(segments)
|
|
328
|
-
expect(rendered).toHaveLength(1)
|
|
329
|
-
expect(rendered[0].streamSeq).toBe(412)
|
|
330
|
-
expect(rendered[0].occurredAt).toEqual(new Date('2026-08-20T14:10:00Z'))
|
|
331
|
-
})
|
|
332
|
-
|
|
333
|
-
it('keeps the hydrated row time over a LATE redelivery arrival stamp', () => {
|
|
334
|
-
// Reconnect catch-up redelivers an hour-old event stamped with its (late)
|
|
335
|
-
// arrival time — the hydrated twin's real row time must win.
|
|
336
|
-
const accumulator = new MessageSegmentAccumulator()
|
|
337
|
-
accumulator.addTicketEvent(
|
|
338
|
-
{ kind: 'RESOLVED', actorId: 'fae', actorName: 'Fae', actorType: 'AI' },
|
|
339
|
-
undefined,
|
|
340
|
-
new Date('2026-08-20T14:10:00Z'),
|
|
341
|
-
)
|
|
342
|
-
const segments = accumulator.addTicketEvent(
|
|
343
|
-
{ kind: 'RESOLVED', actorId: 'fae', actorName: 'Fae', actorType: 'AI' },
|
|
344
|
-
412,
|
|
345
|
-
new Date('2026-08-20T15:10:00Z'),
|
|
346
|
-
)
|
|
347
|
-
const rendered = events(segments)
|
|
348
|
-
expect(rendered).toHaveLength(1)
|
|
349
|
-
expect(rendered[0].occurredAt).toEqual(new Date('2026-08-20T14:10:00Z'))
|
|
350
|
-
})
|
|
351
265
|
})
|
|
@@ -652,9 +652,7 @@ const ChatMessageEnhanced = forwardRef<HTMLDivElement, ChatMessageEnhancedProps>
|
|
|
652
652
|
} else if (segment.type === 'ticket_escalated') {
|
|
653
653
|
return <TicketEscalatedMessage key={index} data={segment.data} timestamp={timestamp} />
|
|
654
654
|
} else if (segment.type === 'ticket_event') {
|
|
655
|
-
|
|
656
|
-
// turn's FIRST row and lags every later lifecycle event.
|
|
657
|
-
return <TicketEventMessage key={index} data={segment.data} timestamp={segment.occurredAt ?? timestamp} />
|
|
655
|
+
return <TicketEventMessage key={index} data={segment.data} timestamp={timestamp} />
|
|
658
656
|
} else if (segment.type === 'error') {
|
|
659
657
|
return (
|
|
660
658
|
<ErrorMessageDisplay
|
|
@@ -1378,13 +1378,7 @@ export function createChatStreamReducer(
|
|
|
1378
1378
|
reason: event.reason,
|
|
1379
1379
|
targetStatusKind: event.targetStatusKind,
|
|
1380
1380
|
}
|
|
1381
|
-
|
|
1382
|
-
// live event that IS the event time. Without it the card falls back to
|
|
1383
|
-
// the enclosing bubble's timestamp: the turn's FIRST row, minutes
|
|
1384
|
-
// stale by the time a resolve/reopen lands. A catch-up redelivery of
|
|
1385
|
-
// an already-hydrated event does NOT regress to arrival time —
|
|
1386
|
-
// `addTicketEvent` keeps the first-known `occurredAt` on upsert.
|
|
1387
|
-
const segments = accumulator.addTicketEvent(data, seq, new Date())
|
|
1381
|
+
const segments = accumulator.addTicketEvent(data, seq)
|
|
1388
1382
|
applyAccumulated(before, segments)
|
|
1389
1383
|
// The card alone is not enough for a host that also tracks the
|
|
1390
1384
|
// ticket's state: a RESOLVED/REOPENED arriving live must move the
|
|
@@ -359,14 +359,6 @@ export type TicketEventSegment = {
|
|
|
359
359
|
type: 'ticket_event'
|
|
360
360
|
data: TicketEventData
|
|
361
361
|
streamSeq?: number
|
|
362
|
-
/** When THIS event happened (history: the persisted row's `createdAt`;
|
|
363
|
-
* live: chunk arrival). Kept beside `streamSeq`, not in `data`: the
|
|
364
|
-
* upsert's payload-equality fallback must keep matching a redelivered
|
|
365
|
-
* chunk to its hydrated twin, and their times come from different clocks.
|
|
366
|
-
* Without it the card inherits the surrounding assistant bubble's
|
|
367
|
-
* timestamp — the FIRST row of the whole turn, so every lifecycle card
|
|
368
|
-
* reads the same stale time. */
|
|
369
|
-
occurredAt?: Date
|
|
370
362
|
}
|
|
371
363
|
|
|
372
364
|
export type ErrorSegment = {
|
|
@@ -550,12 +550,11 @@ export class MessageSegmentAccumulator {
|
|
|
550
550
|
* by the same actor is payload-identical to the first resolve, and matching
|
|
551
551
|
* the old card meant the final one never rendered.
|
|
552
552
|
*/
|
|
553
|
-
addTicketEvent(data: TicketEventData, streamSeq?: number
|
|
553
|
+
addTicketEvent(data: TicketEventData, streamSeq?: number): MessageSegment[] {
|
|
554
554
|
const segment: TicketEventSegment = {
|
|
555
555
|
type: 'ticket_event',
|
|
556
556
|
data,
|
|
557
557
|
...(streamSeq !== undefined ? { streamSeq } : {}),
|
|
558
|
-
...(occurredAt !== undefined ? { occurredAt } : {}),
|
|
559
558
|
}
|
|
560
559
|
let existingIndex =
|
|
561
560
|
streamSeq !== undefined
|
|
@@ -582,13 +581,7 @@ export class MessageSegmentAccumulator {
|
|
|
582
581
|
}
|
|
583
582
|
}
|
|
584
583
|
if (existingIndex !== -1) {
|
|
585
|
-
|
|
586
|
-
// `createdAt`, while a catch-up redelivery only knows its (late) arrival
|
|
587
|
-
// time — replacing wholesale would regress the card to arrival or, with
|
|
588
|
-
// neither side stamped, to the bubble timestamp.
|
|
589
|
-
const existing = this.segments[existingIndex] as TicketEventSegment
|
|
590
|
-
const occurredAt = existing.occurredAt ?? segment.occurredAt
|
|
591
|
-
this.segments[existingIndex] = occurredAt !== undefined ? { ...segment, occurredAt } : segment
|
|
584
|
+
this.segments[existingIndex] = segment
|
|
592
585
|
return this.getSegments()
|
|
593
586
|
}
|
|
594
587
|
this.segments.push(segment)
|
|
@@ -741,7 +734,7 @@ export class MessageSegmentAccumulator {
|
|
|
741
734
|
this.addTicketEscalated(segment.data)
|
|
742
735
|
break
|
|
743
736
|
case 'ticket_event':
|
|
744
|
-
this.addTicketEvent(segment.data, segment.streamSeq
|
|
737
|
+
this.addTicketEvent(segment.data, segment.streamSeq)
|
|
745
738
|
break
|
|
746
739
|
case 'error':
|
|
747
740
|
this.addError(segment.title, segment.details)
|
|
@@ -330,7 +330,6 @@ function applyHistoryEvent(
|
|
|
330
330
|
options: MessageProcessingOptions,
|
|
331
331
|
escalatedApprovals?: EscalatedApprovals,
|
|
332
332
|
offerResolutions?: OfferResolutions,
|
|
333
|
-
rowCreatedAt?: Date,
|
|
334
333
|
): void {
|
|
335
334
|
// batchApprovalsEnabled is owned by the consumer (oss-tenant chat client /
|
|
336
335
|
// openframe-frontend tickets). Defaults to ON so consumers that haven't
|
|
@@ -363,21 +362,14 @@ function applyHistoryEvent(
|
|
|
363
362
|
// same event matches this segment by payload equality (see
|
|
364
363
|
// `addTicketEvent`).
|
|
365
364
|
case 'ticket-event':
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
actorType: event.actorType,
|
|
375
|
-
reason: event.reason,
|
|
376
|
-
targetStatusKind: event.targetStatusKind,
|
|
377
|
-
},
|
|
378
|
-
undefined,
|
|
379
|
-
rowCreatedAt,
|
|
380
|
-
)
|
|
365
|
+
accumulator.addTicketEvent({
|
|
366
|
+
kind: event.kind,
|
|
367
|
+
actorId: event.actorId,
|
|
368
|
+
actorName: event.actorName,
|
|
369
|
+
actorType: event.actorType,
|
|
370
|
+
reason: event.reason,
|
|
371
|
+
targetStatusKind: event.targetStatusKind,
|
|
372
|
+
})
|
|
381
373
|
break
|
|
382
374
|
|
|
383
375
|
case 'escalation-offer-resolved':
|
|
@@ -746,7 +738,6 @@ export function processHistoricalMessages(
|
|
|
746
738
|
{ displayApprovalTypes, batchApprovalsEnabled, escalationOfferStates },
|
|
747
739
|
escalatedApprovals,
|
|
748
740
|
offerResolutions,
|
|
749
|
-
new Date(msg.createdAt),
|
|
750
741
|
)
|
|
751
742
|
})
|
|
752
743
|
|