TL;DR
There are two separate useCookie implementations in the codebase:
packages/stx/src/composables/use-cookie.ts:159-272— TypeScript composable, ~110 lines. Full-featured: JSON serialization, polling-based subscriptions, encode/decode functions,defaultValueresolution,removeCookiehelper,clearCookieshelper.- Runtime template literal in
packages/stx/src/signals.ts— minimal ~30 lines, added under #1701. Regex-based parsing, returns astate()signal, writes viaeffect(), supports basic options (path/maxAge/sameSite).
Both are exposed as window.stx.useCookie and (probably) import { useCookie } from 'stx'. Whichever the consumer's import path lands on, they get different behavior.
How a user can hit it
// Path A: TypeScript module import (might resolve to use-cookie.ts)
import { useCookie } from '@stacksjs/stx'
const token = useCookie<string>('auth-token')
token.subscribe((next, prev) => {/* fires on polling tick */})
// Path B: from inside a <script client> block (resolves via window.stx)
const token = useCookie('auth-token', { maxAge: 3600 })
// no .subscribe; that's not on the runtime versionSame name, same package, two API surfaces.
Why it's bad
- Tests targeting one version don't validate the other (the new tests for #1701 only exercise the runtime version)
- Doc examples written against either version may not work in the other context
- Feature drift compounds — if someone adds a new feature to one impl, the other doesn't get it until manually mirrored
- Future "let me improve useCookie" PRs will touch one impl and assume the other follows; it won't
Proposed fix
Pick one canonical source of truth. The pragmatic choice:
- Module composable wins: signals.ts runtime calls into the composable rather than reimplementing. Requires the composable to be loadable from inside the runtime closure (currently the runtime is generated as a string, so this is non-trivial — would need to inline the composable's source).
- Or runtime wins: composable becomes a thin re-export of whatever
window.stx.useCookieresolves to. Loses tree-shakability for users who only wantuseCookieserver-side.
Either way, the goal is a single behavioral specification and a single set of tests that covers both import paths.
Same pattern likely affects others
Worth checking whether useLocalStorage / useSessionStorage / useEventListener have the same dual-impl pattern. Spot-checking would be useful.
Found during a deep-scan audit.
🤖 Filed via Claude Code