@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.
Files changed (108) hide show
  1. package/dist/chat-protocol/index.cjs.map +1 -1
  2. package/dist/chat-protocol/index.js.map +1 -1
  3. package/dist/{chunk-7FH6MZ6M.cjs → chunk-6OPEULTD.cjs} +9 -9
  4. package/dist/{chunk-7FH6MZ6M.cjs.map → chunk-6OPEULTD.cjs.map} +1 -1
  5. package/dist/{chunk-5MVE77D5.js → chunk-7D62XVHH.js} +6 -6
  6. package/dist/{chunk-6F47STCR.js → chunk-ASULU3T2.js} +2 -2
  7. package/dist/{chunk-26LZFWY6.cjs → chunk-AZPUAPXW.cjs} +17 -25
  8. package/dist/chunk-AZPUAPXW.cjs.map +1 -0
  9. package/dist/{chunk-5JYX2GOP.js → chunk-BK7V6CH5.js} +17 -25
  10. package/dist/chunk-BK7V6CH5.js.map +1 -0
  11. package/dist/{chunk-7IR5LKYC.js → chunk-CP7TMQBH.js} +2 -2
  12. package/dist/{chunk-TXLUKQBI.js → chunk-CQNK6RS6.js} +2 -2
  13. package/dist/{chunk-HJ7OVIR7.js → chunk-DPMOEYEM.js} +2 -2
  14. package/dist/{chunk-CCFBL7JU.cjs → chunk-E6PW7GRQ.cjs} +62 -62
  15. package/dist/{chunk-CCFBL7JU.cjs.map → chunk-E6PW7GRQ.cjs.map} +1 -1
  16. package/dist/{chunk-AN7YK35P.cjs → chunk-FG4BSJ4A.cjs} +26 -26
  17. package/dist/{chunk-AN7YK35P.cjs.map → chunk-FG4BSJ4A.cjs.map} +1 -1
  18. package/dist/{chunk-DEYRHTLD.js → chunk-G2VDS3M5.js} +2 -2
  19. package/dist/{chunk-NCJUIT3Q.cjs → chunk-GEC2NHQH.cjs} +20 -20
  20. package/dist/{chunk-NCJUIT3Q.cjs.map → chunk-GEC2NHQH.cjs.map} +1 -1
  21. package/dist/{chunk-HWQ5HMJN.cjs → chunk-J7R3VZL5.cjs} +14 -14
  22. package/dist/{chunk-HWQ5HMJN.cjs.map → chunk-J7R3VZL5.cjs.map} +1 -1
  23. package/dist/{chunk-5K3F5AZX.js → chunk-NQ6UF4LP.js} +4 -4
  24. package/dist/{chunk-GCMASPSW.js → chunk-NUKQWLOG.js} +5 -5
  25. package/dist/{chunk-3FBPPKV2.js → chunk-O3SEC45L.js} +4 -4
  26. package/dist/{chunk-HVS56KQE.cjs → chunk-OYFXHET4.cjs} +7 -7
  27. package/dist/{chunk-HVS56KQE.cjs.map → chunk-OYFXHET4.cjs.map} +1 -1
  28. package/dist/{chunk-LOLVMAT3.cjs → chunk-PKCZL56Y.cjs} +4 -4
  29. package/dist/{chunk-LOLVMAT3.cjs.map → chunk-PKCZL56Y.cjs.map} +1 -1
  30. package/dist/{chunk-ISK6LRRY.cjs → chunk-PT4GS4CE.cjs} +3 -3
  31. package/dist/{chunk-ISK6LRRY.cjs.map → chunk-PT4GS4CE.cjs.map} +1 -1
  32. package/dist/{chunk-6RILRC7X.js → chunk-T3P56JKN.js} +2 -2
  33. package/dist/{chunk-MIBKEMZY.js → chunk-TDYF6Q2D.js} +2 -2
  34. package/dist/{chunk-32QBTN5L.cjs → chunk-U5EVZLL5.cjs} +5 -5
  35. package/dist/{chunk-32QBTN5L.cjs.map → chunk-U5EVZLL5.cjs.map} +1 -1
  36. package/dist/{chunk-TGT3JHVU.cjs → chunk-VVDLVCPW.cjs} +39 -39
  37. package/dist/{chunk-TGT3JHVU.cjs.map → chunk-VVDLVCPW.cjs.map} +1 -1
  38. package/dist/{chunk-TFEL2C6I.cjs → chunk-WGDZW237.cjs} +86 -86
  39. package/dist/{chunk-TFEL2C6I.cjs.map → chunk-WGDZW237.cjs.map} +1 -1
  40. package/dist/{chunk-QQFUJ6MS.js → chunk-X4JKXYY5.js} +2 -2
  41. package/dist/{chunk-NM5NBMMD.cjs → chunk-XFI5PCER.cjs} +31 -31
  42. package/dist/{chunk-NM5NBMMD.cjs.map → chunk-XFI5PCER.cjs.map} +1 -1
  43. package/dist/{chunk-TFRJ7B4X.cjs → chunk-YFLSOYX4.cjs} +11 -11
  44. package/dist/{chunk-TFRJ7B4X.cjs.map → chunk-YFLSOYX4.cjs.map} +1 -1
  45. package/dist/{chunk-UK6SSMUR.js → chunk-Z4VU6MJ4.js} +2 -2
  46. package/dist/components/case-studies/index.cjs +8 -8
  47. package/dist/components/case-studies/index.js +2 -2
  48. package/dist/components/chat/chat-message-enhanced.d.ts.map +1 -1
  49. package/dist/components/chat/index.cjs +2 -2
  50. package/dist/components/chat/index.js +1 -1
  51. package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +1 -1
  52. package/dist/components/chat/types/message.types.d.ts +0 -8
  53. package/dist/components/chat/types/message.types.d.ts.map +1 -1
  54. package/dist/components/chat/utils/message-segment-accumulator.d.ts +1 -1
  55. package/dist/components/chat/utils/message-segment-accumulator.d.ts.map +1 -1
  56. package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
  57. package/dist/components/contact/index.cjs +3 -3
  58. package/dist/components/contact/index.js +2 -2
  59. package/dist/components/docs/index.cjs +5 -5
  60. package/dist/components/docs/index.js +4 -4
  61. package/dist/components/embeds/index.cjs +3 -3
  62. package/dist/components/embeds/index.js +2 -2
  63. package/dist/components/faq/index.cjs +3 -3
  64. package/dist/components/faq/index.js +2 -2
  65. package/dist/components/features/index.cjs +2 -2
  66. package/dist/components/features/index.js +1 -1
  67. package/dist/components/help-center-pages/index.cjs +22 -22
  68. package/dist/components/help-center-pages/index.js +13 -13
  69. package/dist/components/index.cjs +131 -131
  70. package/dist/components/index.js +11 -11
  71. package/dist/components/meeting-scheduler/index.cjs +30 -30
  72. package/dist/components/meeting-scheduler/index.js +3 -3
  73. package/dist/components/navigation/index.cjs +2 -2
  74. package/dist/components/navigation/index.js +1 -1
  75. package/dist/components/onboarding-guides/index.cjs +5 -5
  76. package/dist/components/onboarding-guides/index.js +4 -4
  77. package/dist/components/related-content/index.cjs +3 -3
  78. package/dist/components/related-content/index.js +2 -2
  79. package/dist/components/tickets/index.cjs +6 -6
  80. package/dist/components/tickets/index.js +5 -5
  81. package/dist/components/ui/index.cjs +2 -2
  82. package/dist/components/ui/index.js +1 -1
  83. package/dist/index.cjs +2 -2
  84. package/dist/index.js +1 -1
  85. package/dist/utils/index.cjs.map +1 -1
  86. package/dist/utils/index.js.map +1 -1
  87. package/package.json +1 -1
  88. package/src/components/chat/__tests__/ticket-event.test.ts +0 -86
  89. package/src/components/chat/chat-message-enhanced.tsx +1 -3
  90. package/src/components/chat/stream/chat-stream-reducer.ts +1 -7
  91. package/src/components/chat/types/message.types.ts +0 -8
  92. package/src/components/chat/utils/message-segment-accumulator.ts +3 -10
  93. package/src/components/chat/utils/process-historical-messages.ts +8 -17
  94. package/dist/chunk-26LZFWY6.cjs.map +0 -1
  95. package/dist/chunk-5JYX2GOP.js.map +0 -1
  96. /package/dist/{chunk-5MVE77D5.js.map → chunk-7D62XVHH.js.map} +0 -0
  97. /package/dist/{chunk-6F47STCR.js.map → chunk-ASULU3T2.js.map} +0 -0
  98. /package/dist/{chunk-7IR5LKYC.js.map → chunk-CP7TMQBH.js.map} +0 -0
  99. /package/dist/{chunk-TXLUKQBI.js.map → chunk-CQNK6RS6.js.map} +0 -0
  100. /package/dist/{chunk-HJ7OVIR7.js.map → chunk-DPMOEYEM.js.map} +0 -0
  101. /package/dist/{chunk-DEYRHTLD.js.map → chunk-G2VDS3M5.js.map} +0 -0
  102. /package/dist/{chunk-5K3F5AZX.js.map → chunk-NQ6UF4LP.js.map} +0 -0
  103. /package/dist/{chunk-GCMASPSW.js.map → chunk-NUKQWLOG.js.map} +0 -0
  104. /package/dist/{chunk-3FBPPKV2.js.map → chunk-O3SEC45L.js.map} +0 -0
  105. /package/dist/{chunk-6RILRC7X.js.map → chunk-T3P56JKN.js.map} +0 -0
  106. /package/dist/{chunk-MIBKEMZY.js.map → chunk-TDYF6Q2D.js.map} +0 -0
  107. /package/dist/{chunk-QQFUJ6MS.js.map → chunk-X4JKXYY5.js.map} +0 -0
  108. /package/dist/{chunk-UK6SSMUR.js.map → chunk-Z4VU6MJ4.js.map} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flamingo-stack/openframe-frontend-core",
3
- "version": "0.0.564-snapshot.20260824155539",
3
+ "version": "0.0.564",
4
4
  "description": "Shared design system and components for all Flamingo platforms",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -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
- // The card's own event time; the bubble timestamp is the
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
- // The chunk carries no event time, so stamp arrival — for a genuinely
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, occurredAt?: Date): MessageSegment[] {
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
- // The FIRST-known time wins: the hydrated twin carries the row's real
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, segment.occurredAt)
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
- // `rowCreatedAt` is the persisted row's own time — without it the card
367
- // renders the enclosing assistant bubble's timestamp, i.e. the FIRST
368
- // row of the turn, and every lifecycle card reads the same stale time.
369
- accumulator.addTicketEvent(
370
- {
371
- kind: event.kind,
372
- actorId: event.actorId,
373
- actorName: event.actorName,
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