wallet-sdk PR3: auth + user#1121
Conversation
Implement AuthDomain + UserDomain, replacing PR2's auth/user NotImplemented
stubs with real impls wired into Sdk.create (Slice 1 of the build plan).
AuthDomain (re-housed framework-free from app/features/user/auth.ts +
shared/auth.ts): signIn / signUp / signInGuest / signOut / refresh /
resetPassword / changePassword / upgradeGuest / beginGoogleSignIn /
completeOAuth. Strips the React/TanStack/window plumbing; sign-in paths
resolve the agicash User (the wallet.users DB row keyed by the OpenSecret
user id) and emit auth:signed-in; sign-out emits auth:signed-out. OAuth is a
browser redirect ({ authUrl }), web-only. No getCurrentSession (contract
decision 4).
UserDomain (re-housed from user-hooks + user-repository): getCurrentUser()
(enclave id -> DB row -> User, or null) + updateUsername() (throws DomainError
on a taken username -> Postgres 23505).
Internals added: OpenSecretClient gains the OS-SDK auth wrappers + hasSession()
(re-houses isLoggedIn onto the StorageAdapter); UserRepository (wallet.users
get + username update over the SDK-owned Supabase client); SessionResolver
(shared id->User + auth:* emission); db-user mapper; framework-free crypto
(password + sha256) and guest-account storage. The Supabase token provider now
short-circuits to null when signed out.
Tests: db-user mapper (full/guest/null defaults), UserRepository (get +
NotFound + the taken-username -> DomainError path + payload assertion),
SessionResolver (null/resolved/emit), AuthDomainImpl (guest new-vs-stored
branching, reset hashes the secret, OAuth forwarding, delegations), UserDomain,
crypto helpers (known SHA-256 vectors). 64 wallet-sdk tests pass; web-wallet
133 pass; full CI (root test both packages + tsc + biome format/lint) green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
| * untyped) Supabase client reads in this slice; replaced by the generated `Database` | ||
| * types when those are lifted into the package. | ||
| */ | ||
| export type AgicashDbUser = { |
There was a problem hiding this comment.
we don't need to redefine these types. we need to keep generating them from the db.
i forgot to mention that in discord chats but migrations should also live in the sdk lib. Everything related to wallet db schema is basically wallet sdk domain and should live there
|
Superseded by the reactive design-B stack (SDK #1129-#1138 + lib-extract #1140-#1143). This no-cache stack was the reference substrate the reactive PRs were built from (~90% reused, reads adapted to Query); it was never reviewed/merged, so nothing is lost. Closing as superseded — branch retained for reference. |
PR3 of the
@agicash/wallet-sdkbuild, stacked on PR2 (#1120). Implements Slice 1 (auth + user) of the no-cache contract (§4) — replacing PR2's auth/userNotImplementedstubs with real implementations wired intoSdk.create.Implemented
AuthDomain(re-housed framework-free fromapp/features/user/auth.ts+shared/auth.ts):signIn/signUp/signInGuest/signOut/refresh/resetPassword/changePassword/upgradeGuest/beginGoogleSignIn/completeOAuth.react-router/windowplumbing. The OpenSecret SDK calls + token/session handling become plain async methods.User(thewallet.usersDB row keyed by the OpenSecret user id) and emitauth:signed-in; sign-out emitsauth:signed-out.StorageAdapter, notwindow.localStorage).beginGoogleSignIn → { authUrl }), web-only. NogetCurrentSession(contract decision 4 — methods returnUser, not a session; the JWT stays SDK-internal).UserDomain(re-housed fromuser-hooks.tsx+user-repository.ts):getCurrentUser()— enclave id → DB row →User, ornullwhen signed out.updateUsername(username)— throwsDomainErrorwhen the username is taken (Postgres23505unique-violation; master raisedUniqueConstraintError).Internals added:
OpenSecretClientgains the OS-SDK auth wrappers +hasSession()(re-houses master'sisLoggedInonto theStorageAdapter).UserRepository—wallet.usersget + username update over the SDK-owned Supabase client.SessionResolver— the sharedid → Userresolution +auth:*emission (both domains use it).db-usermapper, framework-freecrypto(password + SHA-256) andguest-account-storage.nullwhen signed out (matches mastersupabase-session.ts).Lifted vs re-housed
ReadUserRepository.toUser→dbUserToUser;WriteUserRepository.updateusername path;computeSHA256;generateRandomPassword(offwindow.crypto);isLoggedIn(offwindow.localStorage).useAuthActionsbody, the guest new-vs-stored branch,useUser/useUpdateUsername.updateUsernameas a first-class method (master had it UI-only);auth:signed-in/auth:signed-outemission; the session-token signed-out guard.Still stubbed (later slices)
accounts + scan (S2), cashu + spark (S3), transactions + contacts + transfers (S4), background + realtime (S5), exchangeRate.
CI (full script, locally green)
biome format --write packages/wallet-sdk→ cleanbun --filter='*' run test→@agicash/wallet-sdk64 pass / 0 fail,web-wallet133 pass / 0 fail (both exit 0)tsc --noEmit,biome format(check),biome lint→ all cleanTests added:
dbUserToUser(full/guest/null defaults),UserRepository(get + NotFound + the taken-username → DomainError path + write-payload assertion),SessionResolver(null/resolved/emit),AuthDomainImpl(guest branching, reset-hashes-the-secret, OAuth forwarding, delegations),UserDomainImpl, crypto helpers (known SHA-256 vectors).🤖 Generated with Claude Code