Skip to content

Commit 1f4200d

Browse files
committed
docs: update docs
1 parent 6aca6d9 commit 1f4200d

1 file changed

Lines changed: 59 additions & 0 deletions

File tree

‎ai-docs/ai-migration-v14-v15.md‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,65 @@ To ingest an ad-hoc channel (e.g. navigating to a DM or search result) into the
6565

6666
`Channel` no longer reflects the channel-list query state. Its loading / error / empty rendering is driven by the channel's own `watch()` bootstrap (`LoadingIndicator` while watching, `LoadingErrorIndicator` on watch failure, `EmptyPlaceholder` when no channel is provided). The channel-list query state is the `ChannelList`'s concern, not `Channel`'s.
6767

68+
## Dates on response types are unix-nanosecond numbers
69+
70+
`stream-chat` now types every **server-sent** date as the unix-nanosecond `number` the API puts on the
71+
wire — `created_at`, `updated_at`, `last_read`, and every sibling on a response or event. It is not a
72+
`Date` and not an ISO string, and the React types that carry those values through changed with it.
73+
74+
Two failure modes are silent, because neither is a type error:
75+
76+
- `new Date(ns)` is **out of range**. `Date` tops out near 8.64e15 ms while a current timestamp is
77+
~1.79e18, so you get an `Invalid Date` — and `.toISOString()` on one throws
78+
`RangeError: Invalid time value`, usually mid-render.
79+
- Date libraries read a bare number as **milliseconds**, so `dayjs(created_at)` renders a date roughly
80+
50,000 years out without complaining.
81+
82+
### The three public React types that changed
83+
84+
| Type | v14 | v15 |
85+
| ----------------------------------------------------- | ----------------------------- | ------------------------------- |
86+
| `ChatContextValue.latestMessageDatesByChannels` | `Record<ChannelConfId, Date>` | `Record<ChannelConfId, number>` |
87+
| `ProcessMessagesParams.lastRead` (`processMessages`) | `Date \| null` | `number \| null` |
88+
| `VirtualizedMessageList` render props: `lastReadDate` | `Date \| null` | `number \| null` |
89+
90+
Comparisons get simpler, not harder — compare and sort the raw numbers and drop the `Date` round-trip:
91+
92+
```ts
93+
// v14
94+
if (latestMessageDatesByChannels[cid].getTime() < new Date(message.created_at).getTime()) { … }
95+
96+
// v15
97+
if (latestMessageDatesByChannels[cid] < message.created_at) { … }
98+
```
99+
100+
### Presentational props still take `Date`
101+
102+
The conversion boundary is where core data enters the component tree, so components that exist to
103+
_render_ a date are unchanged — `DateSeparator`'s `date: Date` and `formatDate?: (date: Date) => string`,
104+
for instance. Convert at that boundary with the guarded helper `stream-chat` exports:
105+
106+
```ts
107+
import { convertTimestampToDate } from 'stream-chat';
108+
109+
// `undefined` for an absent or non-finite value, so an optional timestamp renders nothing
110+
// instead of throwing RangeError.
111+
<DateSeparator date={convertTimestampToDate(message.created_at)} />
112+
```
113+
114+
`nsToDate` / `dateToNs` / `nsToMs` / `msToNs` / `nowNs` are exported alongside it for values known to be
115+
present. Note that **outgoing request** date fields are still `Date` (filter bounds like
116+
`created_at_before`, plus `remind_at` and `message_timestamp`) — `JSON.stringify` emits RFC3339 for a
117+
`Date`, which is what the request spec declares. Use `nsToDate` when handing a server-sent timestamp
118+
back to the API.
119+
120+
### Test fixtures have to model the wire
121+
122+
A fixture that hands the SDK a `Date` cannot catch either failure mode above, and will diverge from
123+
runtime behavior. The SDK's own suite normalizes through
124+
`mock-builders/generator/time.ts` (`convertDateToTimestamp`), which accepts a `Date`, an ISO string or a
125+
raw wire number so tests stay readable while the value on the wire stays a number.
126+
68127
## i18n: English-only bundle, namespaced translation keys
69128

70129
Two breaking changes, both of which fail **silently** — no error, no compile break unless the app

0 commit comments

Comments
 (0)