@entropy-softworks/ui 2026.8.32 → 2026.8.34
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/lib/components/auth/LockOverlay.d.ts +1 -3
- package/lib/components/auth/LockOverlay.d.ts.map +1 -1
- package/lib/components/auth/LockOverlay.jsx +1 -7
- package/lib/components/auth/LockOverlay.jsx.map +1 -1
- package/lib/utils/index.d.ts +1 -1
- package/lib/utils/index.d.ts.map +1 -1
- package/lib/utils/index.js +1 -1
- package/lib/utils/index.js.map +1 -1
- package/lib/utils/settings-storage.d.ts +9 -0
- package/lib/utils/settings-storage.d.ts.map +1 -1
- package/lib/utils/settings-storage.js +45 -0
- package/lib/utils/settings-storage.js.map +1 -1
- package/package.json +1 -1
- package/src/components/auth/LockOverlay.tsx +0 -20
- package/src/utils/__tests__/settings-storage.test.ts +23 -1
- package/src/utils/index.ts +1 -1
- package/src/utils/settings-storage.ts +46 -0
|
@@ -5,8 +5,6 @@ interface LockOverlayProps {
|
|
|
5
5
|
* password — the overlay catches and surfaces a generic error.
|
|
6
6
|
*/
|
|
7
7
|
onUnlock: (password: string) => Promise<void> | void;
|
|
8
|
-
/** Fired when the user picks "Sign out". */
|
|
9
|
-
onSignOut: () => void;
|
|
10
8
|
/** Optional success-toast message. Defaults to `${appName} unlocked`. */
|
|
11
9
|
successMessage?: string;
|
|
12
10
|
/**
|
|
@@ -41,6 +39,6 @@ interface LockOverlayProps {
|
|
|
41
39
|
* unlock work begins so the fiber tree no longer references the
|
|
42
40
|
* plaintext during PBKDF2 / WebCrypto derivation.
|
|
43
41
|
*/
|
|
44
|
-
export declare function LockOverlay({ onUnlock,
|
|
42
|
+
export declare function LockOverlay({ onUnlock, successMessage, onBiometricUnlock, autoPromptBiometric, }: LockOverlayProps): React.JSX.Element;
|
|
45
43
|
export {};
|
|
46
44
|
//# sourceMappingURL=LockOverlay.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LockOverlay.d.ts","sourceRoot":"","sources":["../../../src/components/auth/LockOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAiB3D,UAAU,gBAAgB;IACxB;;;OAGG;IACH,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACrD,
|
|
1
|
+
{"version":3,"file":"LockOverlay.d.ts","sourceRoot":"","sources":["../../../src/components/auth/LockOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAiB3D,UAAU,gBAAgB;IACxB;;;OAGG;IACH,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACrD,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;;;;;OAWG;IACH,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC/C;;;;;;;;;OASG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,cAAc,EACd,iBAAiB,EACjB,mBAA0B,GAC3B,EAAE,gBAAgB,qBAqMlB"}
|
|
@@ -15,7 +15,7 @@ import { useAppConfig } from "../../context/AppConfigContext";
|
|
|
15
15
|
* unlock work begins so the fiber tree no longer references the
|
|
16
16
|
* plaintext during PBKDF2 / WebCrypto derivation.
|
|
17
17
|
*/
|
|
18
|
-
export function LockOverlay({ onUnlock,
|
|
18
|
+
export function LockOverlay({ onUnlock, successMessage, onBiometricUnlock, autoPromptBiometric = true, }) {
|
|
19
19
|
const { appName, Logo } = useAppConfig();
|
|
20
20
|
const { colorScheme } = useColorScheme();
|
|
21
21
|
const isDark = colorScheme === "dark";
|
|
@@ -125,9 +125,6 @@ export function LockOverlay({ onUnlock, onSignOut, successMessage, onBiometricUn
|
|
|
125
125
|
{biometricState === "prompting" ? "Authenticating…" : "Tap to unlock"}
|
|
126
126
|
</MutedText>
|
|
127
127
|
</Pressable>
|
|
128
|
-
<Text className="mt-10 text-xs text-muted-foreground dark:text-neutral-500" onPress={onSignOut} accessibilityRole="button" accessibilityLabel="Sign out">
|
|
129
|
-
Sign out
|
|
130
|
-
</Text>
|
|
131
128
|
</View>);
|
|
132
129
|
}
|
|
133
130
|
return (<View className="flex-1 items-center justify-center bg-background dark:bg-black">
|
|
@@ -161,9 +158,6 @@ export function LockOverlay({ onUnlock, onSignOut, successMessage, onBiometricUn
|
|
|
161
158
|
{onBiometricUnlock ? (<Button variant="outline" className="w-full" onPress={() => setMode("biometric")} accessibilityLabel="Unlock with biometrics instead" accessibilityRole="button" testID="lock-retry-biometric-button">
|
|
162
159
|
Unlock with Biometrics Instead
|
|
163
160
|
</Button>) : null}
|
|
164
|
-
<Button variant="ghost" className="w-full" onPress={onSignOut} accessibilityLabel="Sign out" accessibilityRole="button">
|
|
165
|
-
Sign out
|
|
166
|
-
</Button>
|
|
167
161
|
</View>
|
|
168
162
|
</View>
|
|
169
163
|
</View>);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LockOverlay.jsx","sourceRoot":"","sources":["../../../src/components/auth/LockOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,MAAM,4BAA4B,CAAC;AAC/C,OAAO,QAAQ,EAAE,EACf,MAAM,EACN,gBAAgB,EAChB,cAAc,EACd,UAAU,EACV,UAAU,GACX,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"LockOverlay.jsx","sourceRoot":"","sources":["../../../src/components/auth/LockOverlay.tsx"],"names":[],"mappings":"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"}
|
package/lib/utils/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { cn } from "./cn";
|
|
|
3
3
|
export { getErrorMessage } from "./error";
|
|
4
4
|
export { darkPalette, getPalette, lightPalette, usePalette, type ColorScheme, type Palette, } from "./palette";
|
|
5
5
|
export { clearClipboardNow, copyToClipboard } from "./clipboard";
|
|
6
|
-
export { loadSetting, saveSetting } from "./settings-storage";
|
|
6
|
+
export { loadSetting, saveSetting, loadJsonSetting, saveJsonSetting } from "./settings-storage";
|
|
7
7
|
export { debounce } from "./debounce";
|
|
8
8
|
export { ApiError, extractApiError, extractErrorMessage } from "./http-error";
|
|
9
9
|
export { generatePassword, type GeneratePasswordOptions } from "./password";
|
package/lib/utils/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EACL,WAAW,EACX,UAAU,EACV,YAAY,EACZ,UAAU,EACV,KAAK,WAAW,EAChB,KAAK,OAAO,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EACL,WAAW,EACX,UAAU,EACV,YAAY,EACZ,UAAU,EACV,KAAK,WAAW,EAChB,KAAK,OAAO,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAChG,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAC5E,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC"}
|
package/lib/utils/index.js
CHANGED
|
@@ -3,7 +3,7 @@ export { cn } from "./cn";
|
|
|
3
3
|
export { getErrorMessage } from "./error";
|
|
4
4
|
export { darkPalette, getPalette, lightPalette, usePalette, } from "./palette";
|
|
5
5
|
export { clearClipboardNow, copyToClipboard } from "./clipboard";
|
|
6
|
-
export { loadSetting, saveSetting } from "./settings-storage";
|
|
6
|
+
export { loadSetting, saveSetting, loadJsonSetting, saveJsonSetting } from "./settings-storage";
|
|
7
7
|
export { debounce } from "./debounce";
|
|
8
8
|
export { ApiError, extractApiError, extractErrorMessage } from "./http-error";
|
|
9
9
|
export { generatePassword } from "./password";
|
package/lib/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EACL,WAAW,EACX,UAAU,EACV,YAAY,EACZ,UAAU,GAGX,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EACL,WAAW,EACX,UAAU,EACV,YAAY,EACZ,UAAU,GAGX,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAChG,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAgC,MAAM,YAAY,CAAC;AAC5E,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,gBAAgB,GAGjB,MAAM,cAAc,CAAC"}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
export declare function loadSetting(key: string, fallback: boolean): Promise<boolean>;
|
|
2
2
|
export declare function saveSetting(key: string, value: boolean): Promise<void>;
|
|
3
|
+
/**
|
|
4
|
+
* Same storage backend as load/saveSetting (SecureStore native,
|
|
5
|
+
* localStorage web) but for arbitrary JSON-serializable values instead
|
|
6
|
+
* of only booleans — e.g. an ordered list of ids, or a per-id map.
|
|
7
|
+
* `fallback` covers both "never saved" and "saved value doesn't parse"
|
|
8
|
+
* (a corrupt/edited-by-hand entry shouldn't crash the caller).
|
|
9
|
+
*/
|
|
10
|
+
export declare function loadJsonSetting<T>(key: string, fallback: T): Promise<T>;
|
|
11
|
+
export declare function saveJsonSetting<T>(key: string, value: T): Promise<void>;
|
|
3
12
|
//# sourceMappingURL=settings-storage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-storage.d.ts","sourceRoot":"","sources":["../../src/utils/settings-storage.ts"],"names":[],"mappings":"AA+BA,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAkBlF;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB5E"}
|
|
1
|
+
{"version":3,"file":"settings-storage.d.ts","sourceRoot":"","sources":["../../src/utils/settings-storage.ts"],"names":[],"mappings":"AA+BA,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAkBlF;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB5E;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAkB7E;AAED,wBAAsB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB7E"}
|
|
@@ -59,4 +59,49 @@ export async function saveSetting(key, value) {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Same storage backend as load/saveSetting (SecureStore native,
|
|
64
|
+
* localStorage web) but for arbitrary JSON-serializable values instead
|
|
65
|
+
* of only booleans — e.g. an ordered list of ids, or a per-id map.
|
|
66
|
+
* `fallback` covers both "never saved" and "saved value doesn't parse"
|
|
67
|
+
* (a corrupt/edited-by-hand entry shouldn't crash the caller).
|
|
68
|
+
*/
|
|
69
|
+
export async function loadJsonSetting(key, fallback) {
|
|
70
|
+
try {
|
|
71
|
+
const raw = Platform.OS === "web"
|
|
72
|
+
? WEB_STORAGE_AVAILABLE
|
|
73
|
+
? window.localStorage.getItem(key)
|
|
74
|
+
: null
|
|
75
|
+
: await SecureStore.getItemAsync(key);
|
|
76
|
+
if (raw === null) {
|
|
77
|
+
return fallback;
|
|
78
|
+
}
|
|
79
|
+
return JSON.parse(raw);
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
if (__DEV__) {
|
|
83
|
+
console.warn(`[settings-storage] loadJsonSetting(${key}) threw:`, e);
|
|
84
|
+
}
|
|
85
|
+
return fallback;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export async function saveJsonSetting(key, value) {
|
|
89
|
+
try {
|
|
90
|
+
const raw = JSON.stringify(value);
|
|
91
|
+
if (Platform.OS === "web") {
|
|
92
|
+
if (!WEB_STORAGE_AVAILABLE) {
|
|
93
|
+
warnNoStorage("save");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
window.localStorage.setItem(key, raw);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
await SecureStore.setItemAsync(key, raw);
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
if (__DEV__) {
|
|
103
|
+
console.warn(`[settings-storage] saveJsonSetting(${key}) threw:`, e);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
62
107
|
//# sourceMappingURL=settings-storage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-storage.js","sourceRoot":"","sources":["../../src/utils/settings-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AAEjD;;;;;;;;GAQG;AAEH,MAAM,qBAAqB,GACzB,QAAQ,CAAC,EAAE,KAAK,KAAK,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;AAElF,IAAI,eAAe,GAAG,KAAK,CAAC;AAC5B,SAAS,aAAa,CAAC,MAAuB;IAC5C,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO;IACT,CAAC;IACD,eAAe,GAAG,IAAI,CAAC;IACvB,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;IACT,CAAC;IAED,OAAO,CAAC,IAAI,CACV,sBAAsB,MAAM,sEAAsE,CACnG,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW,EAAE,QAAiB;IAC9D,IAAI,CAAC;QACH,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;YAC1B,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAC3B,aAAa,CAAC,MAAM,CAAC,CAAC;gBACtB,OAAO,QAAQ,CAAC;YAClB,CAAC;YACD,MAAM,CAAC,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC3C,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC9C,CAAC;QACD,MAAM,CAAC,GAAG,MAAM,WAAW,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QAC9C,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC9C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,2BAA2B,GAAG,UAAU,EAAE,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW,EAAE,KAAc;IAC3D,IAAI,CAAC;QACH,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;YAC1B,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAC3B,aAAa,CAAC,MAAM,CAAC,CAAC;gBACtB,OAAO;YACT,CAAC;YACD,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAChD,OAAO;QACT,CAAC;QACD,MAAM,WAAW,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,2BAA2B,GAAG,UAAU,EAAE,CAAC,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"settings-storage.js","sourceRoot":"","sources":["../../src/utils/settings-storage.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -21,8 +21,6 @@ interface LockOverlayProps {
|
|
|
21
21
|
* password — the overlay catches and surfaces a generic error.
|
|
22
22
|
*/
|
|
23
23
|
onUnlock: (password: string) => Promise<void> | void;
|
|
24
|
-
/** Fired when the user picks "Sign out". */
|
|
25
|
-
onSignOut: () => void;
|
|
26
24
|
/** Optional success-toast message. Defaults to `${appName} unlocked`. */
|
|
27
25
|
successMessage?: string;
|
|
28
26
|
/**
|
|
@@ -60,7 +58,6 @@ interface LockOverlayProps {
|
|
|
60
58
|
*/
|
|
61
59
|
export function LockOverlay({
|
|
62
60
|
onUnlock,
|
|
63
|
-
onSignOut,
|
|
64
61
|
successMessage,
|
|
65
62
|
onBiometricUnlock,
|
|
66
63
|
autoPromptBiometric = true,
|
|
@@ -196,14 +193,6 @@ export function LockOverlay({
|
|
|
196
193
|
{biometricState === "prompting" ? "Authenticating…" : "Tap to unlock"}
|
|
197
194
|
</MutedText>
|
|
198
195
|
</Pressable>
|
|
199
|
-
<Text
|
|
200
|
-
className="mt-10 text-xs text-muted-foreground dark:text-neutral-500"
|
|
201
|
-
onPress={onSignOut}
|
|
202
|
-
accessibilityRole="button"
|
|
203
|
-
accessibilityLabel="Sign out"
|
|
204
|
-
>
|
|
205
|
-
Sign out
|
|
206
|
-
</Text>
|
|
207
196
|
</View>
|
|
208
197
|
);
|
|
209
198
|
}
|
|
@@ -265,15 +254,6 @@ export function LockOverlay({
|
|
|
265
254
|
Unlock with Biometrics Instead
|
|
266
255
|
</Button>
|
|
267
256
|
) : null}
|
|
268
|
-
<Button
|
|
269
|
-
variant="ghost"
|
|
270
|
-
className="w-full"
|
|
271
|
-
onPress={onSignOut}
|
|
272
|
-
accessibilityLabel="Sign out"
|
|
273
|
-
accessibilityRole="button"
|
|
274
|
-
>
|
|
275
|
-
Sign out
|
|
276
|
-
</Button>
|
|
277
257
|
</View>
|
|
278
258
|
</View>
|
|
279
259
|
</View>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as SecureStore from "expo-secure-store";
|
|
2
|
+
import { loadJsonSetting, loadSetting, saveJsonSetting, saveSetting } from "../settings-storage";
|
|
2
3
|
|
|
3
4
|
describe("settings-storage (native path)", () => {
|
|
4
5
|
it("returns the fallback when nothing is stored", async () => {
|
|
@@ -13,3 +14,24 @@ describe("settings-storage (native path)", () => {
|
|
|
13
14
|
expect(await loadSetting("vault_setting_alpha", true)).toBe(false);
|
|
14
15
|
});
|
|
15
16
|
});
|
|
17
|
+
|
|
18
|
+
describe("loadJsonSetting / saveJsonSetting", () => {
|
|
19
|
+
it("returns the fallback when nothing is stored", async () => {
|
|
20
|
+
expect(await loadJsonSetting("vault_json_unset", ["default"])).toEqual(["default"]);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("round-trips an array via SecureStore", async () => {
|
|
24
|
+
await saveJsonSetting("vault_json_tags", ["tag-1", "tag-2", "tag-3"]);
|
|
25
|
+
expect(await loadJsonSetting("vault_json_tags", [])).toEqual(["tag-1", "tag-2", "tag-3"]);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("round-trips an object via SecureStore", async () => {
|
|
29
|
+
await saveJsonSetting("vault_json_map", { "tag-1": true, "tag-2": false });
|
|
30
|
+
expect(await loadJsonSetting("vault_json_map", {})).toEqual({ "tag-1": true, "tag-2": false });
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("falls back on corrupt stored JSON instead of throwing", async () => {
|
|
34
|
+
await SecureStore.setItemAsync("vault_json_corrupt", "{not valid json");
|
|
35
|
+
expect(await loadJsonSetting("vault_json_corrupt", ["fallback"])).toEqual(["fallback"]);
|
|
36
|
+
});
|
|
37
|
+
});
|
package/src/utils/index.ts
CHANGED
|
@@ -10,7 +10,7 @@ export {
|
|
|
10
10
|
type Palette,
|
|
11
11
|
} from "./palette";
|
|
12
12
|
export { clearClipboardNow, copyToClipboard } from "./clipboard";
|
|
13
|
-
export { loadSetting, saveSetting } from "./settings-storage";
|
|
13
|
+
export { loadSetting, saveSetting, loadJsonSetting, saveJsonSetting } from "./settings-storage";
|
|
14
14
|
export { debounce } from "./debounce";
|
|
15
15
|
export { ApiError, extractApiError, extractErrorMessage } from "./http-error";
|
|
16
16
|
export { generatePassword, type GeneratePasswordOptions } from "./password";
|
|
@@ -66,3 +66,49 @@ export async function saveSetting(key: string, value: boolean): Promise<void> {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Same storage backend as load/saveSetting (SecureStore native,
|
|
72
|
+
* localStorage web) but for arbitrary JSON-serializable values instead
|
|
73
|
+
* of only booleans — e.g. an ordered list of ids, or a per-id map.
|
|
74
|
+
* `fallback` covers both "never saved" and "saved value doesn't parse"
|
|
75
|
+
* (a corrupt/edited-by-hand entry shouldn't crash the caller).
|
|
76
|
+
*/
|
|
77
|
+
export async function loadJsonSetting<T>(key: string, fallback: T): Promise<T> {
|
|
78
|
+
try {
|
|
79
|
+
const raw =
|
|
80
|
+
Platform.OS === "web"
|
|
81
|
+
? WEB_STORAGE_AVAILABLE
|
|
82
|
+
? window.localStorage.getItem(key)
|
|
83
|
+
: null
|
|
84
|
+
: await SecureStore.getItemAsync(key);
|
|
85
|
+
if (raw === null) {
|
|
86
|
+
return fallback;
|
|
87
|
+
}
|
|
88
|
+
return JSON.parse(raw) as T;
|
|
89
|
+
} catch (e) {
|
|
90
|
+
if (__DEV__) {
|
|
91
|
+
console.warn(`[settings-storage] loadJsonSetting(${key}) threw:`, e);
|
|
92
|
+
}
|
|
93
|
+
return fallback;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export async function saveJsonSetting<T>(key: string, value: T): Promise<void> {
|
|
98
|
+
try {
|
|
99
|
+
const raw = JSON.stringify(value);
|
|
100
|
+
if (Platform.OS === "web") {
|
|
101
|
+
if (!WEB_STORAGE_AVAILABLE) {
|
|
102
|
+
warnNoStorage("save");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
window.localStorage.setItem(key, raw);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
await SecureStore.setItemAsync(key, raw);
|
|
109
|
+
} catch (e) {
|
|
110
|
+
if (__DEV__) {
|
|
111
|
+
console.warn(`[settings-storage] saveJsonSetting(${key}) threw:`, e);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|