Add kv-wasm: the core compiled to WebAssembly for the web vault
New crate crates/kv-wasm runs the same crypto, item model and sync engine in the browser: - WebStore: in-memory replica of kv-store's Store, each changed entry written to IndexedDB (ciphertext only) before the JS call resolves. - Device key: non-extractable WebCrypto ECDSA P-256 key in IndexedDB (raw r||s signatures). - WebCore mirrors kv-ffi's VaultCore; wasm-bindgen surface in camelCase with TypeScript types, plus a Web Worker wrapper (connectVault) so Argon2id never blocks the page. - Tests: Chrome (IndexedDB, WebCrypto, RFC 9421 verify), shared envelope fixtures both ways with kv-ffi, native sync with kv-ffi via the test server, Node smoke of the built package. Small changes to shared crates so they build for wasm32: - kv-store: SqliteStore moved to a native-only module. - kv-sync: rustls/pinning/tokio native only (fetch on wasm); DeviceSigner::sign_async (default wraps sign) used by ApiClient; unix_now() instead of SystemTime/now_utc. - kv-model: Public Suffix List behind a default `psl` feature (kv-ffi keeps it; the web build drops ~0.9 MB of code and matches same-host only). - wasm-release profile (opt-level z, Argon2 at 3) and a wasm CI job. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
import type {
|
||||
VaultCore,
|
||||
CoreError,
|
||||
CoreErrorCode,
|
||||
generatePassword,
|
||||
totpCode,
|
||||
matchUrl,
|
||||
coreVersion,
|
||||
} from "./kv_wasm.js";
|
||||
|
||||
export * from "./kv_wasm.js";
|
||||
|
||||
type Async<F> = F extends (...args: infer A) => infer R ? (...args: A) => Promise<Awaited<R>> : never;
|
||||
|
||||
type CoreMethods = {
|
||||
[K in keyof VaultCore as K extends "free" | typeof Symbol.dispose ? never : K]: Async<VaultCore[K]>;
|
||||
};
|
||||
|
||||
/** `VaultCore` running in a Web Worker: same methods, all async, plus the free functions. */
|
||||
export type RemoteVault = CoreMethods & {
|
||||
generatePassword: Async<typeof generatePassword>;
|
||||
totpCode: Async<typeof totpCode>;
|
||||
matchUrl: Async<typeof matchUrl>;
|
||||
coreVersion: Async<typeof coreVersion>;
|
||||
/** Frees the core (zeroizing keys), releases the tab lock and terminates the worker. */
|
||||
close(): Promise<void>;
|
||||
};
|
||||
|
||||
/** `"InUse"`: another tab already has this vault open (one tab per vault). */
|
||||
export type ClientErrorCode = CoreErrorCode | "InUse";
|
||||
|
||||
export interface ConnectOptions {
|
||||
/** IndexedDB database name. Default "kestrove". */
|
||||
dbName?: string;
|
||||
/** Persist nothing (previews, tests). */
|
||||
inMemory?: boolean;
|
||||
/** Bring your own worker (e.g. a bundler's `new Worker(new URL(...))`). It must run worker.js. */
|
||||
worker?: Worker;
|
||||
}
|
||||
|
||||
export function connectVault(options?: ConnectOptions): Promise<RemoteVault>;
|
||||
Reference in New Issue
Block a user