Ultimate

5.x → 6.0.0, entry by entry

Installable As of 2026-08-21 — npm view @ultimat3/core version answers 7.0.0, so 6.0.0 is behind latest and every entry below is a step you take on the way to it. Run that command anyway rather than trusting this line; a version written into a page goes stale on the next tag.

Seven breaking entries, and the first is a runtime refusal with no compile error in front of it.

Start here — the one edit

Every single-label timezone name except UTC is refused. isValidTimeZone answers false, canonicalTimeZone answers undefined, assertTimeZone throws X_TIMEZONE_INVALID — and every @ultimat3/time formatter is downstream of that one call. 43 names change answer, tabulated once under the 6.0.0 section of CHANGELOG.md; that table is the source and is deliberately not copied here.

- formatDate(at, { locale, zone: 'CET' })
+ formatDate(at, { locale, zone: 'Europe/Paris' })

Which class the name is in decides whether the swap is mechanical

ClassNamesReplacement
geographic link — 24 of the 43Japan, GB, Hongkong, NZ, …the Area/Location spelling: Asia/Tokyo, Europe/London, Asia/Hong_Kong, Pacific/Auckland. Textual — identical wall clock, identical offset
UTC aliasUCT, Universal, ZuluUTC
the GMT familyGMT, GMT0, GMT+0, GMT-0, GreenwichEtc/GMT, which still renders the label GMT. Not UTC, which renders UTC — same instant, different text on any surface that prints the zone name
abbreviationCET, EET, MET, WET, EST, MST, HST, EST5EDT, CST6CDT, MST7MDT, PST8PDTnone, and that is the defect. An abbreviation names no jurisdiction and carries no DST rule, so only the author knows which city's clock was meant: Europe/Paris for CET, America/New_York for EST5EDT, America/Phoenix for MST

Etc/GMT+2 is unaffected — only a leading sign is a bare offset, and that + sits inside a real zone name. US/Eastern and Asia/Calcutta are unaffected too: a deprecated two-label alias is still Area/Location.

Where the names hide, and why no build error finds them

TimeZone is string in @ultimat3/time, so 'CET' compiles. Nothing fails until the call runs.

SiteSpellingAt 6.0.0
a formatter, or zone arithmeticzone: on formatDate, formatDateTime, formatRange, zonePartsAt, …throws X_TIMEZONE_INVALID on the first call
a scheduled tasktz: on task()refused where the task is declared — task() validates through isValidTimeZone, so this one is caught at boot
app.config.tsdefaultTimeZonerefused at boot — defineConfig validates through core's own statement of the structural rule, so a stale key is X_CONFIG_INVALID naming the field, with the swap in its fix:
a client's x-timezone headerany of the 43no error — resolveTimeZone falls through to the configured default, so a hand-written client sending CET silently renders in your default zone. Browsers are unaffected: Intl.DateTimeFormat().resolvedOptions().timeZone is always Area/Location

Find every candidate:

grep -rnE "(zone|tz|defaultTimeZone): *'[^/']+'" --include='*.ts' --include='*.tsx' .

Run it from the app root. Every hit is a single-label zone; 'UTC' is the only one already correct.

Why it changed

Intl answers "can I format this", never "is this an IANA zone", and at ICU 78 the two stopped agreeing: Bun 1.4 resolves CET, EST, GMT and MST where ICU 75 threw. A runtime upgrade alone therefore reopened the "no date without an explicit IANA zone" rule — silently, and in the direction that fails dangerous, because an abbreviation carries no DST rule. The judgement is now structural instead of delegated: an identifier is Area/Location, and UTC is the one legal exception. That refuses the single-label backward links along with the abbreviations, and is meant to — no structural rule keeps CET out while letting Japan in, both being one label, and the alternative is a denylist that grows with every tzdata release. #251, and Timezones and dates for the rule it restores.

Fixed, and neither costs an edit

FixWhat changes for you
island JSX compiles through babel-preset-solidclient-side Solid reactivity inside an island works at all. An island containing JSX compiled to React.createElement and threw ReferenceError: React is not defined on first interaction, with the gate green. Two build-time dependencies join @ultimat3/cli; zero bytes reach your client bundle (#243)
@ultimat3/core loads in a browser bundlecore's three module-scope AsyncLocalStorage constructions — the request context, the active span, the impersonation reason — moved onto one lazy seam, so @ultimat3/ui no longer throws TypeError: undefined is not a constructor at module evaluation (#244). Six more constructions outside core were untouched at 6.0.0 and carry the same defect — @ultimat3/db, @ultimat3/entity, @ultimat3/ai; they are [Unreleased], along with the guard that makes the rule a build error (#255)

Rebuild to pick either up.

Edit this page on GitHubThis page as markdown