@alwith/module-auth
TypeScript side of the alwith-auth capability, colocated with its separately licensed Rust crate.
Owns the existing Desktop auth types, password rule, OAuth PKCE/in-flight verifier, error-key mapping, request contracts, state lifecycle and token-storage operations. The host supplies its existing store; authStoreName preserves the auth. namespace. Tokens remain in the same store with the same keys. Logout preserves device_id.
This does not move credentials to Rust, replace HTTP, render a login page, or implement cross-device account synchronization. The framework-neutral state factory keeps Desktop's existing restoration, login, logout and window-event semantics; the host supplies storage, HTTP, event transport and product effects. Desktop still owns native OAuth callbacks, windows, provider loading and analytics. U consumes the shared package; OAuth callbacks remain host-specific.
License and redistribution
See LICENSE and third-party notices. ALwith-owned code is proprietary, not open source. You may build, customize, host, charge for and distribute your own applications under the included license, without per-application registration. This does not grant hosted-service access or rights to separately distributed Rust libraries or Runtime binaries. The npm artifact includes compiled/minified JS, declarations and necessary assets, not the private TS/TSX implementation or source maps. Minification is not encryption.
Vibemon assets
@alwith/module-auth/vibemon is a framework-independent account asset service. Inject authenticated requests, account identity and revision, storage, binary resource IO, and cancellable downloads. It exposes the existing catalog, album, draw, first-visit, points, selection and cache contracts. Selection is local and ownership is verified against the service. Resource caches preserve the existing catalog and legacy account directories, config.json, sheet names, and resource versions. Persisted album snapshots only support offline presentation; they do not authorize new draws or change server ownership.
Vibemon behavior and React
The vibemon capability has three independent entry points:
@alwith/module-auth/vibemon: account assets, selection, downloads and cache IO. No React dependency.@alwith/module-auth/vibemon/core: host contracts, state machine, session binding, sprite configuration and resource synchronization. No React, CSS or native window implementation.@alwith/module-auth/vibemon/react: vibemon center, overlay, quick reply and mode button. React and React DOM must be supplied by the host.
Import @alwith/module-auth/vibemon/styles.css once and load translations from
@alwith/module-auth/vibemon/locales. Include node_modules/@alwith/module-auth/dist/vibemon
in the host's Tailwind source scan. Package-relative images, videos, fonts and
sprite URLs are emitted by the host's Vite build with its configured base path.
Videos remain separate files; no public-directory staging is required.
The host injects account assets, storage, session observations and window actions
through VibemonHost. Native window lifecycle, panels, placement and dragging
remain the host's responsibility. A drag promise resolves after mouse release;
the UI thread must remain available to render animation frames during dragging.
Prompt responses acknowledge acceptance; runtime state establishes completion.
Only live transitions trigger completion animation, not replayed snapshots.
Format 1 resources are downloaded from resource_url as complete ZIP packages.
The cache retains the ZIP, manifest, images and animation together, and compares
format, revision and source URL against a fresh API descriptor before reuse.
Paths, SHA-256 hashes, image decoding and animation bounds are validated before
replacing the installed directory. Failed updates retain the previous package;
missing optional images and animation use static placeholders.
Fresh gacha pool items can supply vibemon_resource_url: an unchanged immutable
URL reuses a validated format-1 cache without another detail request. Cold caches,
changed URLs and legacy resources still fetch the descriptor to determine format
and revision. Entry loading includes the home and Wish images so opening Wish
does not start a second loading screen.
Draw results fetch
/api/v1/vibemons/{uuid} to obtain the full package descriptor. Format 0 and
missing format fields continue to use legacy sheet resources.
Hosts may supply resources.url to serve cached images directly and
validateImage to validate their platform decoder before installation.
onResourceError reports failed updates without discarding existing resources.
Legacy asset caches store layout, sheet identity and resource version. Playback defaults
are generated by createSpriteConfig in the core entry. spriteConfig preserves
legacy config.json timing, crop, facing and behavior overrides without rewriting
existing caches. Storage keys and account cache paths remain unchanged; the selected Vibemon is
saved in the vibemon field of vibemon.accounts, so a selection saved under the former field name is
not read and is chosen again once.
Run bun test src and bun check --no-script from this package before building.
bun run build emits minified JavaScript and declarations; bun pm pack includes
those outputs, visual assets and redistribution notices.
Authenticated HTTP transport
createAuthTransport (also available from @alwith/module-auth/transport) owns
API request retries and refresh coordination. Supply baseUrl, fetch, the
result of createTokenStorage, refresh(token), and expired() for this app.
Requests accept /api/v1/ paths; pass authenticated = false for login and
verification-code calls so they never send stored credentials.
Concurrent authentication failures share one refresh. A delayed failure for an
already rotated token retries with the current token. Only refresh failures with
kind: "unauthorized" expire credentials; temporary failures preserve login.
Before replacing or clearing an account, await transport.invalidate(), then
save the new credentials or clear the old ones. This waits for an in-flight token
save and prevents late refresh results from restoring the previous account.
Native refresh and app-specific expiry side effects remain supplied by the host.
Native refresh bridge
Token refresh runs in the private native auth library, shipped in this package under native/
and staged with the application's other module libraries. The public Tauri plugin is the crate
alwith-auth on crates.io; it contains no authentication implementation and owns
no credential store.
alwith-auth = "0.6"
Register .plugin(alwith_auth::init(Config { development_directory, vibemon: None }))
and add alwith-auth:default to the permitted windows. Development may supply its staged native
directory; release builds always resolve the bundle's native folder. Bind
createTauriAuthRefresh() from @alwith/module-auth/tauri (it calls commands.refreshTokens
from @alwith/module-auth/commands), then pass refresh: token => refreshTokens(apiBaseUrl, token)
to createAuthTransport. A rejected refresh is a NativeError { code, message, kind, status? }:
code equals the refresh error kind (unauthorized, network, timeout, server, parse) and
kind is kept beside it, so error.code === "unauthorized" and error.kind === "unauthorized"
both identify expired credentials; status carries the HTTP status where there is one. Only
unauthorized expires the login. Login pages remain replaceable application source.
Rust code that refreshes without a webview (a host's background job holding the stored refresh
token) calls alwith_auth::refresh_tokens(api_base_url, refresh_token).await. It
shares the serialized refresh and its reuse window with the command and fails with the same coded
NativeError (error.code == "unauthorized", error.details["kind"]). The plugin's setup
configures the native library directory; outside it call alwith_native_client::configure_host
first.
Default desktop vibemon
@alwith/module-auth/vibemon/tauri supplies the shared desktop resource, window and session host. Configure VibemonApplication once per webview using the application's auth store, existing Codex client, Runtime connection, account-scoped storage and navigation callbacks. In the main window call initializeVibemonMain; report the visible conversation using updateMainVibemonSurface. Vibemon and bubble windows call bootstrapVibemonWindow before rendering VibemonWindow or VibemonQuickReply.
Enable vibemon in the auth plugin with Config { vibemon: Some(VibemonOwner::new(owner)), .. }, where owner verifies the current execution owner against the host's existing Runtime before each vibemon request. Vibemon policy (window authorization, validation, bubble presentation, claims, resources, downloads) runs in the private native library; the plugin performs only the window actions. Add alwith-auth:vibemon for the main and vibemon windows, and bundle vibemon.html and vibemon-bubble.html. Resource downloads and IPC requests fail explicitly without automatic retries.
Account integration is optional at project creation. Bare chat projects omit this package, native auth, their permissions and vibemon entrypoints; model provider authentication remains independent.