@rajeev02/vault 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # @rajeev02/vault
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@rajeev02/vault.svg)](https://www.npmjs.com/package/@rajeev02/vault)
4
+ [![license](https://img.shields.io/npm/l/@rajeev02/vault.svg)](https://github.com/Rajeev02/rajeev-sdk/blob/main/LICENSE)
5
+
6
+ **AES-256-GCM encrypted key-value storage** with namespaces, expiry, hashing, and biometric gating — powered by Rust for maximum performance and security.
7
+
8
+ Part of [Rajeev SDK](https://github.com/Rajeev02/rajeev-sdk) — cross-platform infrastructure libraries for building apps that work everywhere.
9
+
10
+ ## Why use this?
11
+
12
+ - **Bank-grade encryption** — AES-256-GCM (the same standard used by banks and governments)
13
+ - **Rust-powered** — Crypto logic runs in native Rust, not JavaScript. No key exposure in JS memory.
14
+ - **Offline-first** — SQLite-backed storage works without network. Data persists across app restarts.
15
+ - **Biometric gating** — Optionally require Face ID / Touch ID / fingerprint before reading sensitive keys
16
+ - **Namespaces + expiry** — Organize keys by context, auto-expire tokens after TTL
17
+ - **Truly cross-platform** — Same API on iOS, Android, Web (WASM), watchOS, and Wear OS
18
+
19
+ ## Platform Support
20
+
21
+ | Platform | Engine | Status |
22
+ | ------------ | ----------------- | ------ |
23
+ | iOS 16+ | Rust → UniFFI | ✅ |
24
+ | Android 7+ | Rust → UniFFI JNI | ✅ |
25
+ | Web | Rust → WASM | ✅ |
26
+ | watchOS 9+ | Rust → UniFFI | ✅ |
27
+ | Wear OS | Rust → UniFFI | ✅ |
28
+ | Android Auto | Rust → UniFFI | ✅ |
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ npm install @rajeev02/vault
34
+
35
+ # iOS (after install)
36
+ cd ios && pod install
37
+ ```
38
+
39
+ ### Peer Dependencies
40
+
41
+ - `react` >= 18.3.0
42
+ - `react-native` >= 0.84.0
43
+ - `expo` >= 54.0.0 _(optional)_
44
+
45
+ ## Quick Start
46
+
47
+ ```typescript
48
+ import { Vault } from "@rajeev02/vault";
49
+
50
+ // Create an encrypted vault
51
+ const vault = await Vault.create({
52
+ appId: "my-app",
53
+ encryption: "AES-256-GCM",
54
+ });
55
+
56
+ // Store and retrieve secrets
57
+ await vault.set("auth_token", "eyJhbGciOi…");
58
+ const token = await vault.get("auth_token"); // → 'eyJhbGciOi…'
59
+
60
+ // JSON convenience
61
+ await vault.setJSON("profile", { name: "Rajeev", lang: "hi" });
62
+ const profile = await vault.getJSON<{ name: string }>("profile");
63
+
64
+ // Namespaces — isolate data by context
65
+ const userVault = vault.namespace("user-123");
66
+ await userVault.set("preferences", "dark-mode");
67
+
68
+ // Expiry — auto-delete after TTL
69
+ await vault.set("otp", "483921", { expiry: "5m" });
70
+
71
+ // Biometric gating (iOS Face ID / Android fingerprint)
72
+ await vault.set("bank_pin", "8491", { biometricRequired: true });
73
+ const pin = await vault.get("bank_pin"); // triggers biometric prompt
74
+
75
+ // Hashing — one-way hash for password verification
76
+ const hash = await vault.hash("my-password");
77
+ const matches = await vault.verifyHash("my-password", hash); // → true
78
+
79
+ // Bulk operations
80
+ await vault.setMany([
81
+ { key: "a", value: "1" },
82
+ { key: "b", value: "2" },
83
+ ]);
84
+ const all = await vault.getAll(); // → Map of all key-value pairs
85
+
86
+ // Cleanup
87
+ await vault.delete("auth_token");
88
+ await vault.clear(); // Remove all keys
89
+ ```
90
+
91
+ ## React Hooks
92
+
93
+ ```typescript
94
+ import { useVault, useVaultValue } from "@rajeev02/vault";
95
+
96
+ function SecureComponent() {
97
+ const vault = useVault({ appId: "my-app" });
98
+ const [token, setToken] = useVaultValue(vault, "auth_token");
99
+
100
+ return <Text>{token ?? "No token"}</Text>;
101
+ }
102
+ ```
103
+
104
+ ## API Reference
105
+
106
+ | Method | Returns | Description |
107
+ | -------------------------------- | ------------------------- | ------------------------------- |
108
+ | `Vault.create(config)` | `Promise<Vault>` | Create encrypted vault instance |
109
+ | `vault.set(key, value, opts?)` | `Promise<void>` | Store encrypted value |
110
+ | `vault.get(key)` | `Promise<string \| null>` | Retrieve decrypted value |
111
+ | `vault.setJSON(key, obj, opts?)` | `Promise<void>` | Store JSON object |
112
+ | `vault.getJSON<T>(key)` | `Promise<T \| null>` | Retrieve parsed JSON |
113
+ | `vault.delete(key)` | `Promise<void>` | Delete a key |
114
+ | `vault.clear()` | `Promise<void>` | Delete all keys |
115
+ | `vault.has(key)` | `Promise<boolean>` | Check if key exists |
116
+ | `vault.keys()` | `Promise<string[]>` | List all keys |
117
+ | `vault.getAll()` | `Promise<Map>` | Get all key-value pairs |
118
+ | `vault.namespace(ns)` | `Vault` | Create namespaced sub-vault |
119
+ | `vault.hash(input)` | `Promise<string>` | One-way hash |
120
+ | `vault.verifyHash(input, hash)` | `Promise<boolean>` | Verify hash match |
121
+
122
+ ## Architecture
123
+
124
+ ```
125
+ TypeScript API (this package)
126
+
127
+ Native Bridge (auto-generated by UniFFI)
128
+
129
+ Rust Core (rajeev-vault-core)
130
+ ├── AES-256-GCM encryption (aes-gcm 0.10)
131
+ ├── SQLite storage (rusqlite 0.38)
132
+ ├── Key derivation (PBKDF2 / Argon2)
133
+ └── Secure random (rand 0.9)
134
+ ```
135
+
136
+ ## Full Documentation
137
+
138
+ 📖 [Complete API docs with platform-specific examples](https://github.com/Rajeev02/rajeev-sdk/blob/main/docs/usage/VAULT.md)
139
+
140
+ ## License
141
+
142
+ MIT © 2026 [Rajeev Kumar Joshi](https://rajeev02.github.io)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rajeev02/vault",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Universal secure storage for React Native — AES-256-GCM encrypted, cross-platform",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -8,7 +8,7 @@
8
8
  "build": "tsc",
9
9
  "clean": "rm -rf lib",
10
10
  "test": "jest",
11
- "prepublishOnly": "yarn build"
11
+ "prepublishOnly": "npm run build"
12
12
  },
13
13
  "keywords": [
14
14
  "react-native",
@@ -24,7 +24,7 @@
24
24
  "repository": {
25
25
  "type": "git",
26
26
  "url": "https://github.com/Rajeev02/rajeev-sdk",
27
- "directory": "packages/vault"
27
+ "directory": "packages/vault/ts-wrapper"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "react": ">=18.3.0",
@@ -44,10 +44,7 @@
44
44
  },
45
45
  "files": [
46
46
  "lib/",
47
- "android/",
48
- "ios/",
49
- "rust-core/",
50
- "rajeev-vault.podspec",
47
+ "src/",
51
48
  "README.md"
52
49
  ],
53
50
  "publishConfig": {
package/src/hooks.ts ADDED
@@ -0,0 +1,169 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { Vault } from './vault';
3
+ import type { VaultConfig, StoreOptions, VaultStats } from './types';
4
+
5
+ /**
6
+ * React hook to create and manage a Vault instance.
7
+ *
8
+ * @param config - Vault configuration
9
+ * @returns Vault instance and loading state
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * function App() {
14
+ * const { vault, isReady, error } = useVault({ appId: 'com.myapp' });
15
+ *
16
+ * if (!isReady) return <LoadingScreen />;
17
+ * if (error) return <ErrorScreen error={error} />;
18
+ *
19
+ * return <MainApp vault={vault!} />;
20
+ * }
21
+ * ```
22
+ */
23
+ export function useVault(config: VaultConfig) {
24
+ const [vault, setVault] = useState<Vault | null>(null);
25
+ const [isReady, setIsReady] = useState(false);
26
+ const [error, setError] = useState<Error | null>(null);
27
+ const initRef = useRef(false);
28
+
29
+ useEffect(() => {
30
+ if (initRef.current) return;
31
+ initRef.current = true;
32
+
33
+ Vault.create(config)
34
+ .then((v) => {
35
+ setVault(v);
36
+ setIsReady(true);
37
+ })
38
+ .catch((e) => {
39
+ setError(e);
40
+ setIsReady(true);
41
+ });
42
+ }, [config.appId]);
43
+
44
+ return { vault, isReady, error };
45
+ }
46
+
47
+ /**
48
+ * React hook to read a value from the vault reactively.
49
+ * Re-reads when the key or namespace changes.
50
+ *
51
+ * @param vault - Vault instance
52
+ * @param key - Key to read
53
+ * @param namespace - Optional namespace
54
+ * @returns Value, loading state, and refresh function
55
+ *
56
+ * @example
57
+ * ```tsx
58
+ * function TokenDisplay({ vault }: { vault: Vault }) {
59
+ * const { value, isLoading, refresh } = useVaultValue(vault, 'auth_token');
60
+ *
61
+ * if (isLoading) return <Text>Loading...</Text>;
62
+ *
63
+ * return (
64
+ * <View>
65
+ * <Text>Token: {value ?? 'Not set'}</Text>
66
+ * <Button title="Refresh" onPress={refresh} />
67
+ * </View>
68
+ * );
69
+ * }
70
+ * ```
71
+ */
72
+ export function useVaultValue(
73
+ vault: Vault | null,
74
+ key: string,
75
+ namespace?: string,
76
+ ) {
77
+ const [value, setValue] = useState<string | null>(null);
78
+ const [isLoading, setIsLoading] = useState(true);
79
+ const [error, setError] = useState<Error | null>(null);
80
+
81
+ const refresh = useCallback(async () => {
82
+ if (!vault) return;
83
+ setIsLoading(true);
84
+ try {
85
+ const result = await vault.get(key, namespace);
86
+ setValue(result);
87
+ setError(null);
88
+ } catch (e) {
89
+ setError(e as Error);
90
+ } finally {
91
+ setIsLoading(false);
92
+ }
93
+ }, [vault, key, namespace]);
94
+
95
+ useEffect(() => {
96
+ refresh();
97
+ }, [refresh]);
98
+
99
+ return { value, isLoading, error, refresh };
100
+ }
101
+
102
+ /**
103
+ * React hook to read a JSON value from the vault.
104
+ *
105
+ * @example
106
+ * ```tsx
107
+ * interface UserProfile {
108
+ * name: string;
109
+ * email: string;
110
+ * }
111
+ *
112
+ * function Profile({ vault }: { vault: Vault }) {
113
+ * const { data, isLoading } = useVaultJSON<UserProfile>(vault, 'profile');
114
+ *
115
+ * if (isLoading) return <Text>Loading...</Text>;
116
+ * return <Text>Hello, {data?.name ?? 'Guest'}</Text>;
117
+ * }
118
+ * ```
119
+ */
120
+ export function useVaultJSON<T = unknown>(
121
+ vault: Vault | null,
122
+ key: string,
123
+ namespace?: string,
124
+ ) {
125
+ const { value, isLoading, error, refresh } = useVaultValue(vault, key, namespace);
126
+
127
+ const data = value ? (JSON.parse(value) as T) : null;
128
+
129
+ return { data, isLoading, error, refresh };
130
+ }
131
+
132
+ /**
133
+ * React hook to get vault statistics.
134
+ *
135
+ * @example
136
+ * ```tsx
137
+ * function VaultInfo({ vault }: { vault: Vault }) {
138
+ * const { stats, isLoading } = useVaultStats(vault);
139
+ *
140
+ * return (
141
+ * <Text>
142
+ * Entries: {stats?.totalEntries ?? 0}
143
+ * Size: {stats?.storageBytes ?? 0} bytes
144
+ * </Text>
145
+ * );
146
+ * }
147
+ * ```
148
+ */
149
+ export function useVaultStats(vault: Vault | null) {
150
+ const [stats, setStats] = useState<VaultStats | null>(null);
151
+ const [isLoading, setIsLoading] = useState(true);
152
+
153
+ const refresh = useCallback(async () => {
154
+ if (!vault) return;
155
+ setIsLoading(true);
156
+ try {
157
+ const s = await vault.stats();
158
+ setStats(s);
159
+ } finally {
160
+ setIsLoading(false);
161
+ }
162
+ }, [vault]);
163
+
164
+ useEffect(() => {
165
+ refresh();
166
+ }, [refresh]);
167
+
168
+ return { stats, isLoading, refresh };
169
+ }
package/src/index.ts ADDED
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @rajeev02/vault
3
+ *
4
+ * Universal Secure Storage for React Native
5
+ * AES-256-GCM encrypted, cross-platform (Android, iOS, Web, Watch, Auto, IoT)
6
+ *
7
+ * Built with Rust core for maximum security and performance.
8
+ *
9
+ * @author Rajeev Kumar Joshi (https://github.com/Rajeev02)
10
+ * @license MIT
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { Vault } from '@rajeev02/vault';
15
+ *
16
+ * const vault = await Vault.create({ appId: 'com.myapp' });
17
+ *
18
+ * // Store
19
+ * await vault.set('token', 'my-secret', { expiry: '24h' });
20
+ *
21
+ * // Retrieve
22
+ * const token = await vault.get('token');
23
+ *
24
+ * // Namespaces
25
+ * const payments = vault.namespace('payments');
26
+ * await payments.set('upi_pin', '1234', { biometricRequired: true });
27
+ *
28
+ * // JSON helpers
29
+ * await vault.setJSON('user', { name: 'Rajeev', role: 'admin' });
30
+ * const user = await vault.getJSON<User>('user');
31
+ * ```
32
+ */
33
+
34
+ // Core
35
+ export { Vault } from './vault';
36
+
37
+ // Types
38
+ export {
39
+ VaultConfig,
40
+ StoreOptions,
41
+ VaultStats,
42
+ VaultError,
43
+ VaultErrorCode,
44
+ } from './types';
45
+
46
+ // React Hooks
47
+ export {
48
+ useVault,
49
+ useVaultValue,
50
+ useVaultJSON,
51
+ useVaultStats,
52
+ } from './hooks';
@@ -0,0 +1,33 @@
1
+ import { NativeModules, Platform } from 'react-native';
2
+ import type { NativeVaultModule } from './types';
3
+
4
+ /**
5
+ * Get the native vault module for the current platform.
6
+ *
7
+ * Android: Uses JNI → Rust .so library
8
+ * iOS: Uses C FFI → Rust .a static library
9
+ * Web: Uses WASM → Rust compiled to WebAssembly
10
+ */
11
+ function getNativeModule(): NativeVaultModule {
12
+ const { RajeevVault } = NativeModules;
13
+
14
+ if (!RajeevVault) {
15
+ throw new Error(
16
+ `@rajeev02/vault: Native module not found. ` +
17
+ `Make sure you have run 'pod install' (iOS) or rebuilt the app (Android).\n\n` +
18
+ `Platform: ${Platform.OS}\n` +
19
+ `If you're on web, import from '@rajeev02/vault/web' instead.`,
20
+ );
21
+ }
22
+
23
+ return RajeevVault as NativeVaultModule;
24
+ }
25
+
26
+ export const NativeBridge = {
27
+ /**
28
+ * Get the native module, lazy-loaded and cached
29
+ */
30
+ get module(): NativeVaultModule {
31
+ return getNativeModule();
32
+ },
33
+ };
package/src/types.ts ADDED
@@ -0,0 +1,131 @@
1
+ /**
2
+ * @rajeev02/vault - Type Definitions
3
+ *
4
+ * Universal secure storage for React Native, Web, Watch, Auto, IoT
5
+ * Built by Rajeev Kumar Joshi (https://github.com/Rajeev02)
6
+ */
7
+
8
+ /** Configuration for creating a vault instance */
9
+ export interface VaultConfig {
10
+ /** Unique app identifier (e.g., 'com.myapp') */
11
+ appId: string;
12
+
13
+ /** Custom database path. Defaults to app-specific location */
14
+ dbPath?: string;
15
+
16
+ /** Encryption algorithm. Default: 'AES-256-GCM' */
17
+ encryption?: 'AES-256-GCM';
18
+
19
+ /** Whether biometric auth is available on this device */
20
+ biometricAvailable?: boolean;
21
+ }
22
+
23
+ /** Options when storing a value */
24
+ export interface StoreOptions {
25
+ /**
26
+ * When the value should expire and auto-delete.
27
+ * Format: "30m" (minutes), "24h" (hours), "7d" (days), "4w" (weeks)
28
+ * Default: null (never expires)
29
+ */
30
+ expiry?: string | null;
31
+
32
+ /**
33
+ * Whether biometric authentication is required to read this value.
34
+ * Default: false
35
+ */
36
+ biometricRequired?: boolean;
37
+
38
+ /**
39
+ * Whether this entry can be exported/backed up.
40
+ * Set to false for highly sensitive data like PINs.
41
+ * Default: true
42
+ */
43
+ exportable?: boolean;
44
+
45
+ /**
46
+ * Namespace to group related entries.
47
+ * e.g., 'auth', 'payments', 'health'
48
+ * Default: 'default'
49
+ */
50
+ namespace?: string;
51
+ }
52
+
53
+ /** Statistics about the vault */
54
+ export interface VaultStats {
55
+ /** Total number of stored entries */
56
+ totalEntries: number;
57
+
58
+ /** Number of distinct namespaces */
59
+ totalNamespaces: number;
60
+
61
+ /** Number of expired entries pending cleanup */
62
+ expiredEntries: number;
63
+
64
+ /** Approximate storage used in bytes */
65
+ storageBytes: number;
66
+ }
67
+
68
+ /** Error codes returned by the vault */
69
+ export enum VaultErrorCode {
70
+ ENCRYPTION_FAILED = 'ENCRYPTION_FAILED',
71
+ DECRYPTION_FAILED = 'DECRYPTION_FAILED',
72
+ KEY_NOT_FOUND = 'KEY_NOT_FOUND',
73
+ KEY_EXPIRED = 'KEY_EXPIRED',
74
+ STORAGE_ERROR = 'STORAGE_ERROR',
75
+ INVALID_CONFIG = 'INVALID_CONFIG',
76
+ BIOMETRIC_REQUIRED = 'BIOMETRIC_REQUIRED',
77
+ BIOMETRIC_FAILED = 'BIOMETRIC_FAILED',
78
+ NOT_INITIALIZED = 'NOT_INITIALIZED',
79
+ }
80
+
81
+ /** Custom error class for vault operations */
82
+ export class VaultError extends Error {
83
+ public readonly code: VaultErrorCode;
84
+
85
+ constructor(code: VaultErrorCode, message?: string) {
86
+ super(message || code);
87
+ this.name = 'VaultError';
88
+ this.code = code;
89
+ }
90
+ }
91
+
92
+ /** Internal native module interface (platform-specific) */
93
+ export interface NativeVaultModule {
94
+ create(config: {
95
+ appId: string;
96
+ dbPath?: string;
97
+ encryptionAlgo: string;
98
+ biometricAvailable: boolean;
99
+ }): Promise<void>;
100
+
101
+ store(
102
+ key: string,
103
+ value: string,
104
+ expiry: string | null,
105
+ biometricRequired: boolean,
106
+ exportable: boolean,
107
+ namespace: string | null,
108
+ ): Promise<void>;
109
+
110
+ retrieve(key: string, namespace: string | null): Promise<string | null>;
111
+ delete(key: string, namespace: string | null): Promise<boolean>;
112
+ exists(key: string, namespace: string | null): Promise<boolean>;
113
+ listKeys(namespace: string | null): Promise<string[]>;
114
+ listNamespaces(): Promise<string[]>;
115
+ wipeNamespace(namespace: string): Promise<void>;
116
+ wipeAll(): Promise<void>;
117
+ getStats(): Promise<VaultStats>;
118
+ cleanupExpired(): Promise<void>;
119
+ exportEntry(key: string, namespace: string | null): Promise<string | null>;
120
+ importEntry(
121
+ key: string,
122
+ encryptedData: string,
123
+ expiry: string | null,
124
+ biometricRequired: boolean,
125
+ exportable: boolean,
126
+ namespace: string | null,
127
+ ): Promise<void>;
128
+ generateKey(): Promise<string>;
129
+ hash(input: string): Promise<string>;
130
+ verifyHash(input: string, hash: string): Promise<boolean>;
131
+ }
package/src/vault.ts ADDED
@@ -0,0 +1,396 @@
1
+ import { NativeBridge } from './native-bridge';
2
+ import {
3
+ VaultConfig,
4
+ StoreOptions,
5
+ VaultStats,
6
+ VaultError,
7
+ VaultErrorCode,
8
+ } from './types';
9
+
10
+ /**
11
+ * 🔐 Rajeev Vault — Universal Secure Storage
12
+ *
13
+ * AES-256-GCM encrypted storage that works across all platforms.
14
+ * Built with Rust core for maximum security and performance.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { Vault } from '@rajeev02/vault';
19
+ *
20
+ * // Create vault
21
+ * const vault = await Vault.create({ appId: 'com.myapp' });
22
+ *
23
+ * // Store securely
24
+ * await vault.set('token', 'my-secret-value', { expiry: '24h' });
25
+ *
26
+ * // Retrieve
27
+ * const token = await vault.get('token');
28
+ *
29
+ * // Use namespaces
30
+ * await vault.namespace('payments').set('upi_pin', '1234', {
31
+ * biometricRequired: true,
32
+ * exportable: false,
33
+ * });
34
+ * ```
35
+ *
36
+ * @author Rajeev Kumar Joshi (https://github.com/Rajeev02)
37
+ */
38
+ export class Vault {
39
+ private initialized = false;
40
+ private config: VaultConfig;
41
+ private currentNamespace: string | null = null;
42
+
43
+ private constructor(config: VaultConfig) {
44
+ this.config = config;
45
+ }
46
+
47
+ /**
48
+ * Create a new Vault instance.
49
+ * This is the main entry point — use this instead of `new Vault()`.
50
+ *
51
+ * @param config - Vault configuration
52
+ * @returns Initialized Vault instance
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * const vault = await Vault.create({
57
+ * appId: 'com.myapp',
58
+ * biometricAvailable: true,
59
+ * });
60
+ * ```
61
+ */
62
+ static async create(config: VaultConfig): Promise<Vault> {
63
+ const vault = new Vault(config);
64
+
65
+ try {
66
+ await NativeBridge.module.create({
67
+ appId: config.appId,
68
+ dbPath: config.dbPath,
69
+ encryptionAlgo: config.encryption || 'AES-256-GCM',
70
+ biometricAvailable: config.biometricAvailable ?? false,
71
+ });
72
+ vault.initialized = true;
73
+ } catch (error) {
74
+ throw new VaultError(
75
+ VaultErrorCode.INVALID_CONFIG,
76
+ `Failed to initialize vault: ${error}`,
77
+ );
78
+ }
79
+
80
+ return vault;
81
+ }
82
+
83
+ /**
84
+ * Ensure the vault is initialized before any operation
85
+ */
86
+ private ensureInitialized(): void {
87
+ if (!this.initialized) {
88
+ throw new VaultError(
89
+ VaultErrorCode.NOT_INITIALIZED,
90
+ 'Vault not initialized. Call Vault.create() first.',
91
+ );
92
+ }
93
+ }
94
+
95
+ // ─── Core Operations ─────────────────────────────────────────────
96
+
97
+ /**
98
+ * Store a value securely.
99
+ *
100
+ * @param key - Unique key for the value
101
+ * @param value - String value to encrypt and store
102
+ * @param options - Storage options (expiry, biometric, namespace)
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * // Simple store
107
+ * await vault.set('token', 'eyJhbG...');
108
+ *
109
+ * // With expiry
110
+ * await vault.set('otp', '4829', { expiry: '5m' });
111
+ *
112
+ * // With biometric protection
113
+ * await vault.set('pin', '1234', {
114
+ * biometricRequired: true,
115
+ * exportable: false,
116
+ * });
117
+ *
118
+ * // Store JSON
119
+ * await vault.set('user', JSON.stringify({ name: 'Rajeev', role: 'admin' }));
120
+ * ```
121
+ */
122
+ async set(key: string, value: string, options?: StoreOptions): Promise<void> {
123
+ this.ensureInitialized();
124
+
125
+ const ns = options?.namespace ?? this.currentNamespace;
126
+
127
+ await NativeBridge.module.store(
128
+ key,
129
+ value,
130
+ options?.expiry ?? null,
131
+ options?.biometricRequired ?? false,
132
+ options?.exportable ?? true,
133
+ ns,
134
+ );
135
+ }
136
+
137
+ /**
138
+ * Retrieve a decrypted value.
139
+ * Returns null if the key doesn't exist or has expired.
140
+ *
141
+ * @param key - Key to retrieve
142
+ * @param namespace - Optional namespace override
143
+ * @returns Decrypted value or null
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * const token = await vault.get('token');
148
+ * if (token) {
149
+ * console.log('Got token:', token);
150
+ * } else {
151
+ * console.log('Token not found or expired');
152
+ * }
153
+ *
154
+ * // Get JSON
155
+ * const userJson = await vault.get('user');
156
+ * const user = userJson ? JSON.parse(userJson) : null;
157
+ * ```
158
+ */
159
+ async get(key: string, namespace?: string): Promise<string | null> {
160
+ this.ensureInitialized();
161
+ const ns = namespace ?? this.currentNamespace;
162
+ return NativeBridge.module.retrieve(key, ns);
163
+ }
164
+
165
+ /**
166
+ * Get a value, parsed as JSON.
167
+ * Convenience method that combines get() + JSON.parse().
168
+ *
169
+ * @param key - Key to retrieve
170
+ * @param namespace - Optional namespace override
171
+ * @returns Parsed object or null
172
+ */
173
+ async getJSON<T = unknown>(key: string, namespace?: string): Promise<T | null> {
174
+ const raw = await this.get(key, namespace);
175
+ if (raw === null) return null;
176
+
177
+ try {
178
+ return JSON.parse(raw) as T;
179
+ } catch {
180
+ return null;
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Store a value as JSON.
186
+ * Convenience method that combines JSON.stringify() + set().
187
+ */
188
+ async setJSON<T>(key: string, value: T, options?: StoreOptions): Promise<void> {
189
+ const serialized = JSON.stringify(value);
190
+ await this.set(key, serialized, options);
191
+ }
192
+
193
+ /**
194
+ * Delete a key from the vault.
195
+ *
196
+ * @param key - Key to delete
197
+ * @param namespace - Optional namespace override
198
+ * @returns true if the key was deleted, false if not found
199
+ */
200
+ async delete(key: string, namespace?: string): Promise<boolean> {
201
+ this.ensureInitialized();
202
+ const ns = namespace ?? this.currentNamespace;
203
+ return NativeBridge.module.delete(key, ns);
204
+ }
205
+
206
+ /**
207
+ * Check if a key exists (and is not expired).
208
+ *
209
+ * @param key - Key to check
210
+ * @param namespace - Optional namespace override
211
+ * @returns true if key exists and is valid
212
+ */
213
+ async has(key: string, namespace?: string): Promise<boolean> {
214
+ this.ensureInitialized();
215
+ const ns = namespace ?? this.currentNamespace;
216
+ return NativeBridge.module.exists(key, ns);
217
+ }
218
+
219
+ // ─── Namespace Operations ─────────────────────────────────────────
220
+
221
+ /**
222
+ * Create a namespace-scoped vault view.
223
+ * All operations on the returned object are scoped to this namespace.
224
+ *
225
+ * @param name - Namespace name
226
+ * @returns Namespace-scoped vault
227
+ *
228
+ * @example
229
+ * ```typescript
230
+ * const payments = vault.namespace('payments');
231
+ * await payments.set('upi_pin', '1234');
232
+ * await payments.set('card_last4', '4242');
233
+ *
234
+ * const health = vault.namespace('health');
235
+ * await health.set('blood_group', 'O+');
236
+ *
237
+ * // Keys don't collide across namespaces
238
+ * await vault.namespace('a').set('key', 'value-a');
239
+ * await vault.namespace('b').set('key', 'value-b');
240
+ * ```
241
+ */
242
+ namespace(name: string): NamespacedVault {
243
+ this.ensureInitialized();
244
+ return new NamespacedVault(this, name);
245
+ }
246
+
247
+ /**
248
+ * List all keys in a namespace.
249
+ *
250
+ * @param namespace - Namespace to list (default namespace if not specified)
251
+ * @returns Array of key names
252
+ */
253
+ async keys(namespace?: string): Promise<string[]> {
254
+ this.ensureInitialized();
255
+ const ns = namespace ?? this.currentNamespace;
256
+ return NativeBridge.module.listKeys(ns);
257
+ }
258
+
259
+ /**
260
+ * List all namespaces in the vault.
261
+ *
262
+ * @returns Array of namespace names
263
+ */
264
+ async namespaces(): Promise<string[]> {
265
+ this.ensureInitialized();
266
+ return NativeBridge.module.listNamespaces();
267
+ }
268
+
269
+ // ─── Destructive Operations ───────────────────────────────────────
270
+
271
+ /**
272
+ * Delete all entries in a namespace.
273
+ *
274
+ * @param namespace - Namespace to wipe
275
+ */
276
+ async wipeNamespace(namespace: string): Promise<void> {
277
+ this.ensureInitialized();
278
+ await NativeBridge.module.wipeNamespace(namespace);
279
+ }
280
+
281
+ /**
282
+ * ⚠️ Delete EVERYTHING in the vault. Cannot be undone.
283
+ * Typically used during logout.
284
+ *
285
+ * @example
286
+ * ```typescript
287
+ * async function logout() {
288
+ * await vault.wipeAll();
289
+ * navigation.reset('LoginScreen');
290
+ * }
291
+ * ```
292
+ */
293
+ async wipeAll(): Promise<void> {
294
+ this.ensureInitialized();
295
+ await NativeBridge.module.wipeAll();
296
+ }
297
+
298
+ // ─── Utility Operations ───────────────────────────────────────────
299
+
300
+ /**
301
+ * Get storage statistics.
302
+ *
303
+ * @returns Stats including entry count, namespaces, storage size
304
+ */
305
+ async stats(): Promise<VaultStats> {
306
+ this.ensureInitialized();
307
+ return NativeBridge.module.getStats();
308
+ }
309
+
310
+ /**
311
+ * Clean up expired entries. Call periodically to reclaim space.
312
+ */
313
+ async cleanup(): Promise<void> {
314
+ this.ensureInitialized();
315
+ await NativeBridge.module.cleanupExpired();
316
+ }
317
+
318
+ // ─── Static Utilities ─────────────────────────────────────────────
319
+
320
+ /**
321
+ * Generate a cryptographically secure random key.
322
+ * Useful for creating encryption keys, API tokens, etc.
323
+ *
324
+ * @returns Base64-encoded random key
325
+ */
326
+ static async generateKey(): Promise<string> {
327
+ return NativeBridge.module.generateKey();
328
+ }
329
+
330
+ /**
331
+ * Hash a value (one-way). Useful for storing passwords.
332
+ *
333
+ * @param input - Value to hash
334
+ * @returns Salted hash string
335
+ */
336
+ static async hash(input: string): Promise<string> {
337
+ return NativeBridge.module.hash(input);
338
+ }
339
+
340
+ /**
341
+ * Verify a value against a hash.
342
+ *
343
+ * @param input - Value to verify
344
+ * @param hash - Hash to verify against
345
+ * @returns true if the value matches the hash
346
+ */
347
+ static async verifyHash(input: string, hash: string): Promise<boolean> {
348
+ return NativeBridge.module.verifyHash(input, hash);
349
+ }
350
+ }
351
+
352
+ /**
353
+ * A namespace-scoped view of the vault.
354
+ * All operations are automatically scoped to the namespace.
355
+ */
356
+ class NamespacedVault {
357
+ private vault: Vault;
358
+ private name: string;
359
+
360
+ constructor(vault: Vault, name: string) {
361
+ this.vault = vault;
362
+ this.name = name;
363
+ }
364
+
365
+ async set(key: string, value: string, options?: Omit<StoreOptions, 'namespace'>): Promise<void> {
366
+ return this.vault.set(key, value, { ...options, namespace: this.name });
367
+ }
368
+
369
+ async get(key: string): Promise<string | null> {
370
+ return this.vault.get(key, this.name);
371
+ }
372
+
373
+ async getJSON<T = unknown>(key: string): Promise<T | null> {
374
+ return this.vault.getJSON<T>(key, this.name);
375
+ }
376
+
377
+ async setJSON<T>(key: string, value: T, options?: Omit<StoreOptions, 'namespace'>): Promise<void> {
378
+ return this.vault.setJSON(key, value, { ...options, namespace: this.name });
379
+ }
380
+
381
+ async delete(key: string): Promise<boolean> {
382
+ return this.vault.delete(key, this.name);
383
+ }
384
+
385
+ async has(key: string): Promise<boolean> {
386
+ return this.vault.has(key, this.name);
387
+ }
388
+
389
+ async keys(): Promise<string[]> {
390
+ return this.vault.keys(this.name);
391
+ }
392
+
393
+ async wipe(): Promise<void> {
394
+ return this.vault.wipeNamespace(this.name);
395
+ }
396
+ }