0.9.0
Minor Changes
- #976
engines.nodeis now>=24.0.0, up from>=22.12.0, and Node 22 is no longer supported. Node 24.0.0 is the first release with explicit resource management built in (using,await using,DisposableStack,AsyncDisposableStack,SuppressedError) and all of ES2025, so the packages use both as the platform ships them instead of shimming them for an older line, and the CI matrix runs the unit suite on 24.0.0 itself. Move to Node 24, or stay on the current minor while a deployment still runs Node 22.
Patch Changes
#977 The README states the browser floor: Chrome and Edge 136, Firefox 136, and Safari 18.4 or later, the first releases that ship every ES2025 builtin.
@codefast/di's README also says what a browser program without explicit resource management does: it keepsskipLibCheckon and callsdispose()instead ofawait using.#965
README.mdnow states TypeScript 7 or later as the floor for the package's types — the one compiler every@codefast/*package is built and checked with. No code or declaration changed.
0.8.4
Patch Changes
#892
4c97c5bThanks @thevuong! - Lower the monorepo's Node floor from 24 to 22.12, so the packages install and run on the active Node 22 LTS line.engines.nodebecomes>=22.12.0across every package — the floor the shared toolchain (oxlint, Vite, Vitest, TanStack Start) already requires. Development stays on the latest Node (.node-version) for speed, and a CI matrix exercises the floor and the active LTS directly, so the floor is a contract CI proves rather than one everyone has to run.@types/nodeis pinned to the floor's major (^22), with a workspace override holding the whole tree there so a dev tool's@types/node: "*"peer can no longer pull a newer major and mask an API the floor lacks. The floor stays mechanical, not advisory:@codefast/dikeeps its ownMapupsert helpers rather than the ES2025Map.prototype.getOrInsert(which would raise the floor to 26) and itslibstaysES2024.@codefast/cli's mirror step now calls thenode:pathfunctions directly instead of aliasing them, which the floor's types correctly flag as unbound methods.The shared
@codefast/typescript-configpresets pinlibandtargettoES2024(wasESNext) so the compiler's ECMAScript surface matches the Node floor: an ES2025 builtin such asMap.prototype.getOrInsertnow fails to type-check rather than compiling and crashing on Node 22.12.@codefast/diand@codefast/di-testingalready pinnedliband are unchanged.Internal subpath imports move from a
#/prefix to a bare#(#core/token, not#/core/token), and thepackage.json#importskeys become#*/#tests/*/#examples/*to match. Node's native ESM resolver rejects a#/-prefixed specifier withERR_INVALID_MODULE_SPECIFIERon the whole Node 22 line (and on Node 24 before 24.14), and each package ships those specifiers verbatim inside its publisheddist/*.jsfor a consumer's Node to resolve — so this rename is what actually lets the packages import on the new floor. Purely internal: a consumer's own import paths are unchanged.
0.8.3
Patch Changes
- #850
db17956Thanks @thevuong! - Import Zod as a namespace (import * as z from "zod") so bundlers can tree-shake it. The namedimport { z }kept Zod's full locale set in the bundle; the appearance provider's browser bundle now drops roughly 80% (~91 KB → ~18 KB gzip).
0.8.2
Patch Changes
#812
f051471Thanks @thevuong! - Raise the published dependency floors:zodto 4.5.4 (@codefast/cli,@codefast/theme),lucide-reactto 1.41.0 andreact-hook-formto 7.87.0 (@codefast/ui).#791
37a212bThanks @thevuong! - Point the README's license badge and "License" section at the package's ownLICENSEfile instead of the monorepo root.#796
ba04d27Thanks @thevuong! - Rewrite the README around one structure — what the package is, installation and requirements, a complete quick start, the concepts in learning order, then the documents and the license — with every API claim checked against the current code and no figures that go stale.#784
ad2f93aThanks @thevuong! - Ship the MITLICENSEfile in the published package.filesalready listed it, but the file was missing from the package directory, so the tarball had none.
0.8.1
Patch Changes
- #748
bde6d1bThanks @thevuong! - Mirror the committed appearance ref in a layout effect so a programmaticsetAppearancelanding before the passive flush compares against the just-committed appearance instead of the previous one.
0.8.0
Minor Changes
#745
5cbb93aThanks @thevuong! - fix(theme): harden appearance provider/script and tighten public typesThree correctness fixes plus two type-safety tightenings:
- Overlapping
setAppearancecalls withdisableTransitionenabled could orphan a transition-suppression<style>—enableTransitionsRefwas overwritten before the previous cleanup ran — leaving*{transition:none}in<head>forever and permanently disabling CSS transitions. Each call now flushes the pending suppression before injecting a new one. AppearanceScriptnow runtime-validates itsappearanceprop (asAppearanceProvideralready did), so an invalid value can no longer be written to<html>before first paint or diverge from the provider's fallback.applyColorSchemeno-ops during SSR instead of throwing onwindowaccess, matching its siblingsuppressTransitions.- Public props on
AppearanceProviderandAppearanceScriptnow accept explicitundefined(?: T | undefined) underexactOptionalPropertyTypes, so JSX callers can pass possibly-undefined expressions such asnonceandappearance.
Breaking (type surface only, no runtime behavior change):
appearancesis nowReadonlyArray<Appearance>(wasArray<Appearance>), so assigning it to a mutableAppearance[]is now a compile error.- Overlapping
0.7.0
0.6.2
0.6.1
0.6.0
Patch Changes
#690
f4b1aa6Thanks @thevuong! - Report the failures that were being swallowed or mislabelled, and derive the types the build emits.@codefast/di:@inject,@postConstructand@preDestroyon a static member now throwStaticMemberDecoratorErrorinstead ofInternalError. All three act on one instance, so this is caller misuse — andInternalErrormeans the library broke, which sent anyone catching it to file a bug against their own mistake. SPEC §10 already recorded that mistake for predicate ambiguity.AsyncResolutionErrornames the token the caller asked for and the token whose factory is async, which is what SPEC has always specified. Every throw site passed the same token twice, so the message read "Token 'X' requires async resolution because 'X' in its dependency chain has an async factory"; aresolve(App)that fails on an asyncDatabasenow says so.asyncSourceTokendefaults totokenNamefor the case where the requested binding is itself the source.- A
MetadataReaderthat names a@postConstruct/@preDestroymethod the instance does not have raisesInvalidMetadataErrorinstead of skipping the hook — a hook that silently never runs is the failure a caller cannot see.InvalidMetadataError's message no longer says "constructor", since it now covers both answers; the specifics moved intoreason. MissingScopeContextErrorfromScopeManagernames its token instead of"(unknown)", and the scoped read takes one map lookup where it took two.Token,ConstructorandInjectionDescriptordeclareout Value, so the compiler checks the covariance the engine already relied on.
Repo-wide:
isolatedDeclarationsis on for every package that emits declarations, so a public type can always be written down from the source file alone.allowJsis gone from the shared base config — no package has JavaScript sources.@codefast/themeand@codefast/trackinggained explicit annotations on four exported constants to satisfy it; the emitted types are unchanged.@codefast/uiand@codefast/benchmark-vieweropt out for reasons recorded in their configs.
0.5.0
Minor Changes
c634b17Thanks @thevuong! - RenameAppearanceContextTypetoAppearanceContextValue— the "Type" suffix carried no information (every exported type is a type), while "Value" states the role: the payload provided throughAppearanceContextand returned byuseAppearance.#547
c7d6818Thanks @thevuong! - Add astorageKeyprop toAppearanceProviderfor a fully client-side color scheme path (no server framework, cookie, or loader). When set, the provider reads the persisted preference fromlocalStoragein its initial client render, auto-persists changes there (unless an explicitpersistColorSchemeis given), and syncs across tabs via thestorageevent. Paired with<AppearanceScript storageKey>using the same key, the inline script applies the stored value before first paint — so there is no flash even on statically prerendered / CDN-served pages, where an httpOnly cookie can't reach the pre-paint script and a post-mount server round-trip would otherwise flip the appearance.AppearanceScriptandAppearanceProvidernow also mirror the preference (light/dark/automatic) to adata-appearanceattribute on<html>— set by the inline script before first paint and kept in sync by the provider. This lets preference-aware UI (e.g. a 3-state theme toggle that shows a distinct "system" icon) render the correct state purely from CSS, with no hydration flash from reading client-only state.#526
fad5a21Thanks @thevuong! - Add the@codefast/theme/viteplugin. TanStack Start registers the server functions shipped in@codefast/theme/startat the consumer's build time, so the package must not be externalized for SSR nor pre-bundled for the client. The newcodefastTheme()plugin applies that configuration automatically, so consumers no longer need to hand-writessr.noExternal/optimizeDeps.exclude.
Patch Changes
#676
641e233Thanks @thevuong! - Collapse thetypesanddefaultlanes ofpackage.json#importsfrom fallback arrays to single strings.Node resolves an imports array by taking the first candidate it can parse, without checking that the file exists and without falling through — a specifier whose first candidate is missing throws
ERR_MODULE_NOT_FOUNDrather than trying the second../dist/*/index.jsand./dist/*/index.d.tscould therefore never be reached, so they read as a safety net that does not exist. Thesourcelane keeps its extension candidates, which onlytscand Vite read and both probe.#550
0feb8cdThanks @thevuong! - Rename the public API to follow Apple's Human Interface Guidelines vocabulary: appearance is the user's preference ("light" | "dark" | "automatic", like macOS System Settings → Appearance), color scheme is the resolved light-or-dark value actually applied (like SwiftUIColorSchemeand CSScolor-scheme). Source files are also flattened so each subpath names what it exports.Breaking renames:
Types:
ColorScheme→Appearance;ResolvedColorScheme→ColorScheme;ColorSchemeContextType→AppearanceContextType;colorSchemeSchema→appearanceSchema;colorSchemes→appearances.Hook:
useColorScheme()→useAppearance(), returning{ appearance, colorScheme, setAppearance, isPending }(was{ colorScheme, resolvedColorScheme, setColorScheme, isPending }).Provider props:
colorScheme→appearance;persistColorScheme→persistAppearance. Script prop:colorScheme→appearance. Context:ColorSchemeContext→AppearanceContext.Constants:
DEFAULT_COLOR_SCHEME→DEFAULT_APPEARANCE("automatic");DEFAULT_RESOLVED_COLOR_SCHEME→DEFAULT_COLOR_SCHEME("dark"). ⚠️DEFAULT_COLOR_SCHEMEstill exists but now means the resolved fallback — the prop renames make stale usage a compile error.Subpaths:
./types→./appearance;./core/provider→./appearance-provider;./core/use-theme→./use-appearance;./core/context→./appearance-context;./script/theme-script→./appearance-script;./utils/system→./color-scheme;./utils/dom→./dom.Persisted values: the default
STORAGE_KEYis now"ui-appearance"(was"ui-theme") — returning visitors fall back to"automatic"once. The internalBroadcastChannelis now"appearance-sync"(was"color-scheme-sync").
Unchanged:
AppearanceProvider/AppearanceScriptcomponent names, thedata-appearanceattribute,resolveColorScheme()/getSystemColorScheme()/applyColorScheme()/suppressTransitions().#549
2d16644Thanks @thevuong! - Remove all server-side handling — the color scheme preference now lives entirely on the client inlocalStorage.Breaking:
- Removed
@codefast/theme/start,@codefast/theme/vite, and@codefast/theme/adapters/tanstack-start/server— the TanStack Start server functions, httpOnly cookie persistence, and the Vite plugin that wired them into consumer builds. - Removed
AppearanceProvider'sssrColorSchemeandsyncFromServerprops; the provider also no longer re-syncs from a changedcolorSchemeprop after mount (it is a static fallback now). resolveColorScheme()no longer takes anssrColorSchemeargument; on the server,"automatic"resolves toDEFAULT_RESOLVED_COLOR_SCHEME.- Dropped the optional
@tanstack/react-startandvitepeer dependencies.
Changed defaults:
storageKeynow defaults toSTORAGE_KEY("ui-appearance") andcolorSchemetoDEFAULT_COLOR_SCHEME("automatic") on bothAppearanceScriptandAppearanceProvider, so<AppearanceScript />+<AppearanceProvider>work with zero configuration.persistColorScheme/onPersistErrorremain for custom persistence.Migration: drop the root loader and the
codefastTheme()Vite plugin, render the defaults on<html>withsuppressHydrationWarning, and let the inline script correct the class before paint — see the README's TanStack Start recipe.- Removed
0.5.0-canary.9
Patch Changes
#676
641e233Thanks @thevuong! - Collapse thetypesanddefaultlanes ofpackage.json#importsfrom fallback arrays to single strings.Node resolves an imports array by taking the first candidate it can parse, without checking that the file exists and without falling through — a specifier whose first candidate is missing throws
ERR_MODULE_NOT_FOUNDrather than trying the second../dist/*/index.jsand./dist/*/index.d.tscould therefore never be reached, so they read as a safety net that does not exist. Thesourcelane keeps its extension candidates, which onlytscand Vite read and both probe.
0.5.0-canary.8
0.5.0-canary.7
0.5.0-canary.6
Minor Changes
c634b17Thanks @thevuong! - RenameAppearanceContextTypetoAppearanceContextValue— the "Type" suffix carried no information (every exported type is a type), while "Value" states the role: the payload provided throughAppearanceContextand returned byuseAppearance.#547
c7d6818Thanks @thevuong! - Add astorageKeyprop toAppearanceProviderfor a fully client-side color scheme path (no server framework, cookie, or loader). When set, the provider reads the persisted preference fromlocalStoragein its initial client render, auto-persists changes there (unless an explicitpersistColorSchemeis given), and syncs across tabs via thestorageevent. Paired with<AppearanceScript storageKey>using the same key, the inline script applies the stored value before first paint — so there is no flash even on statically prerendered / CDN-served pages, where an httpOnly cookie can't reach the pre-paint script and a post-mount server round-trip would otherwise flip the appearance.AppearanceScriptandAppearanceProvidernow also mirror the preference (light/dark/automatic) to adata-appearanceattribute on<html>— set by the inline script before first paint and kept in sync by the provider. This lets preference-aware UI (e.g. a 3-state theme toggle that shows a distinct "system" icon) render the correct state purely from CSS, with no hydration flash from reading client-only state.#526
fad5a21Thanks @thevuong! - Add the@codefast/theme/viteplugin. TanStack Start registers the server functions shipped in@codefast/theme/startat the consumer's build time, so the package must not be externalized for SSR nor pre-bundled for the client. The newcodefastTheme()plugin applies that configuration automatically, so consumers no longer need to hand-writessr.noExternal/optimizeDeps.exclude.
Patch Changes
#550
0feb8cdThanks @thevuong! - Rename the public API to follow Apple's Human Interface Guidelines vocabulary: appearance is the user's preference ("light" | "dark" | "automatic", like macOS System Settings → Appearance), color scheme is the resolved light-or-dark value actually applied (like SwiftUIColorSchemeand CSScolor-scheme). Source files are also flattened so each subpath names what it exports.Breaking renames:
Types:
ColorScheme→Appearance;ResolvedColorScheme→ColorScheme;ColorSchemeContextType→AppearanceContextType;colorSchemeSchema→appearanceSchema;colorSchemes→appearances.Hook:
useColorScheme()→useAppearance(), returning{ appearance, colorScheme, setAppearance, isPending }(was{ colorScheme, resolvedColorScheme, setColorScheme, isPending }).Provider props:
colorScheme→appearance;persistColorScheme→persistAppearance. Script prop:colorScheme→appearance. Context:ColorSchemeContext→AppearanceContext.Constants:
DEFAULT_COLOR_SCHEME→DEFAULT_APPEARANCE("automatic");DEFAULT_RESOLVED_COLOR_SCHEME→DEFAULT_COLOR_SCHEME("dark"). ⚠️DEFAULT_COLOR_SCHEMEstill exists but now means the resolved fallback — the prop renames make stale usage a compile error.Subpaths:
./types→./appearance;./core/provider→./appearance-provider;./core/use-theme→./use-appearance;./core/context→./appearance-context;./script/theme-script→./appearance-script;./utils/system→./color-scheme;./utils/dom→./dom.Persisted values: the default
STORAGE_KEYis now"ui-appearance"(was"ui-theme") — returning visitors fall back to"automatic"once. The internalBroadcastChannelis now"appearance-sync"(was"color-scheme-sync").
Unchanged:
AppearanceProvider/AppearanceScriptcomponent names, thedata-appearanceattribute,resolveColorScheme()/getSystemColorScheme()/applyColorScheme()/suppressTransitions().#549
2d16644Thanks @thevuong! - Remove all server-side handling — the color scheme preference now lives entirely on the client inlocalStorage.Breaking:
- Removed
@codefast/theme/start,@codefast/theme/vite, and@codefast/theme/adapters/tanstack-start/server— the TanStack Start server functions, httpOnly cookie persistence, and the Vite plugin that wired them into consumer builds. - Removed
AppearanceProvider'sssrColorSchemeandsyncFromServerprops; the provider also no longer re-syncs from a changedcolorSchemeprop after mount (it is a static fallback now). resolveColorScheme()no longer takes anssrColorSchemeargument; on the server,"automatic"resolves toDEFAULT_RESOLVED_COLOR_SCHEME.- Dropped the optional
@tanstack/react-startandvitepeer dependencies.
Changed defaults:
storageKeynow defaults toSTORAGE_KEY("ui-appearance") andcolorSchemetoDEFAULT_COLOR_SCHEME("automatic") on bothAppearanceScriptandAppearanceProvider, so<AppearanceScript />+<AppearanceProvider>work with zero configuration.persistColorScheme/onPersistErrorremain for custom persistence.Migration: drop the root loader and the
codefastTheme()Vite plugin, render the defaults on<html>withsuppressHydrationWarning, and let the inline script correct the class before paint — see the README's TanStack Start recipe.- Removed
1.0.0-canary.7
1.0.0-canary.6
0.5.0-canary.5
0.5.0-canary.4
Minor Changes
c634b17Thanks @thevuong! - RenameAppearanceContextTypetoAppearanceContextValue— the "Type" suffix carried no information (every exported type is a type), while "Value" states the role: the payload provided throughAppearanceContextand returned byuseAppearance.
0.5.0-canary.3
Showing the latest 20 releases; the full changelog on GitHub has 30 more releases.