@glinr/theauth-lynx package. The framework-neutral session store in @glinr/theauth-client is what a Lynx app uses, and this page says what it needs from the runtime, what I checked and what I did not.
What Better Auth does
Better Auth documents Lynx with abetter-auth/lynx entry that exports createAuthClient and a useStore hook over its nanostores session atom, with @lynx-js/react as the only added dependency. Its page says nothing about cookies, storage or the thread model, so it does not tell you what the runtime needs.
What Lynx gives you
From the Lynx docs (networking, fetch reference, best practices, @lynx-js/react):fetchis provided and described as compatible with the Web API, with “subtle differences”. It needs the HTTP service of the integrated Lynx Service. The compatibility note says Lynx does not support Web-only features like CORS, redirect and keepalive, and thatFormDataandBlobare unsupported.credentials,AbortControllerandsignalare not mentioned.- No web storage. I found no built-in
localStorage. The Lynx native modules guide shows a storage module you write yourself on each platform. - No
TextEncoderorTextDecoderin PrimJS, the JavaScript engine. Lynx shipsTextCodecHelperfor UTF-8. - React 17 API. ReactLynx follows React 17 and skips concurrent features such as
useTransition.useSyncExternalStoreis in the@lynx-js/reactAPI reference. - Two threads. Rendering runs on the main thread. Effects, event handlers and native module calls belong on the background thread, and calling native modules from the main thread blocks the UI.
What the session store needs
The store change that came out of this check:
refresh used new AbortController() unconditionally and would throw where it is missing. It is now optional, and packages/client/tests/session-store-email-password.test.ts runs a full sign up, verify, sign in, refresh, rehydrate and sign out against the real handler with AbortController, window, localStorage, TextEncoder and TextDecoder removed.
Recipe
Sign-in goes through the email and password routes. Lynx has no page origin, sobasePath is an absolute URL. Storage is a native module you implement, and the store persists through it by subscribe and hydrateSession, because native calls are asynchronous and the store’s own storage hook is synchronous.
lib/auth.ts
SignIn.tsx
@lynx-js/react 0.126.0 and @glinr/theauth-client. The thread rules are yours to apply: keep startAuth and the handlers that call store on the background thread.
What a first-class Lynx client would need
I would not add a package yet. If Lynx use turns out to be real, in order:- A device check of
fetchwith the bearer token: does the response body parse, isSet-Cookiekept, doescredentials: "include"do anything. - An async storage option on the session store (
getItemreturning a promise), so the native module recipe collapses into one option. Expo already has this shape inTheAuthStorage. - A thin
useSyncExternalStorehook export from a@glinr/theauth-client/lynxsubpath, which is what Better Auth ships, so users do not copy the hook. - Whether
@glinr/theauth-reactruns unchanged under@lynx-js/react(it usesuseSyncExternalStore,useMemoand the automatic JSX runtime). It is untested, which is why the recipe uses the store directly.