@entropy-softworks/ui 2026.8.17 → 2026.8.18
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.
|
@@ -12,11 +12,32 @@ export interface UseAutoLockOptions {
|
|
|
12
12
|
/** Idle threshold in milliseconds. Defaults to 10 minutes. */
|
|
13
13
|
idleLockMs?: number;
|
|
14
14
|
}
|
|
15
|
+
export interface UseAutoLockResult {
|
|
16
|
+
/**
|
|
17
|
+
* Call on any real user interaction to reset the idle clock. Required
|
|
18
|
+
* on native: unlike web (which listens on `window` for
|
|
19
|
+
* mousemove/touchstart/scroll/keydown directly), RN has no global
|
|
20
|
+
* "any touch happened anywhere" event — a touch inside a `Pressable`,
|
|
21
|
+
* `ScrollView`, etc. never reaches `window`, because there is no
|
|
22
|
+
* `window` to reach. Without a caller wiring this up (e.g. a capture-
|
|
23
|
+
* phase `onStartShouldSetResponderCapture` at the app root, returning
|
|
24
|
+
* `false` so it never actually claims the touch), the idle timer is
|
|
25
|
+
* armed once at mount and never reset — the session locks exactly
|
|
26
|
+
* `idleLockMs` after mount/foreground REGARDLESS of how actively the
|
|
27
|
+
* app is being used. Confirmed for real: a vault mid-active-use lost
|
|
28
|
+
* its key mid-session, and every item silently failed to decrypt
|
|
29
|
+
* (`Promise.allSettled` in the caller's list-fetch treats a decrypt
|
|
30
|
+
* failure as "drop this item", not "the vault relocked"), which reads
|
|
31
|
+
* to the user as vault items simply vanishing — no error, no visible
|
|
32
|
+
* cause, on 2026-08-17.
|
|
33
|
+
*/
|
|
34
|
+
notifyActivity: () => void;
|
|
35
|
+
}
|
|
15
36
|
/**
|
|
16
37
|
* Auto-lock a session after a period of inactivity. Generic over the
|
|
17
38
|
* lock predicate — vault wires `KeyManager.isUnlocked` / `KeyManager.lock`,
|
|
18
39
|
* other apps wire their own state. Web uses an idle-timer only; native
|
|
19
40
|
* additionally locks immediately when the app goes to the background.
|
|
20
41
|
*/
|
|
21
|
-
export declare function useAutoLock(options: UseAutoLockOptions):
|
|
42
|
+
export declare function useAutoLock(options: UseAutoLockOptions): UseAutoLockResult;
|
|
22
43
|
//# sourceMappingURL=useAutoLock.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAutoLock.d.ts","sourceRoot":"","sources":["../../src/hooks/useAutoLock.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,UAAU,EAAE,MAAM,OAAO,CAAC;IAC1B,+DAA+D;IAC/D,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,
|
|
1
|
+
{"version":3,"file":"useAutoLock.d.ts","sourceRoot":"","sources":["../../src/hooks/useAutoLock.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,UAAU,EAAE,MAAM,OAAO,CAAC;IAC1B,+DAA+D;IAC/D,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;;;;;;;;;;;;;;OAiBG;IACH,cAAc,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,CA2F1E"}
|
package/lib/hooks/useAutoLock.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
1
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
2
2
|
import { AppState as RNAppState, Platform } from "react-native";
|
|
3
3
|
const DEFAULT_IDLE_LOCK_MS = 10 * 60 * 1000;
|
|
4
4
|
/**
|
|
@@ -9,6 +9,7 @@ const DEFAULT_IDLE_LOCK_MS = 10 * 60 * 1000;
|
|
|
9
9
|
*/
|
|
10
10
|
export function useAutoLock(options) {
|
|
11
11
|
const { isUnlocked, onLock, isEnabled, idleLockMs = DEFAULT_IDLE_LOCK_MS } = options;
|
|
12
|
+
const onActivityRef = useRef(() => { });
|
|
12
13
|
useEffect(() => {
|
|
13
14
|
let idleTimer = null;
|
|
14
15
|
let lastActivityAt = Date.now();
|
|
@@ -43,6 +44,7 @@ export function useAutoLock(options) {
|
|
|
43
44
|
lastActivityAt = Date.now();
|
|
44
45
|
armIdleTimer();
|
|
45
46
|
};
|
|
47
|
+
onActivityRef.current = onActivity;
|
|
46
48
|
// On web, RN Web's AppState mirrors document visibility — tab-hidden
|
|
47
49
|
// becomes 'background', which would otherwise fire an immediate lock.
|
|
48
50
|
// Only treat 'background' as a lock signal on real native platforms.
|
|
@@ -81,5 +83,9 @@ export function useAutoLock(options) {
|
|
|
81
83
|
};
|
|
82
84
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
83
85
|
}, []);
|
|
86
|
+
const notifyActivity = useCallback(() => {
|
|
87
|
+
onActivityRef.current();
|
|
88
|
+
}, []);
|
|
89
|
+
return { notifyActivity };
|
|
84
90
|
}
|
|
85
91
|
//# sourceMappingURL=useAutoLock.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAutoLock.js","sourceRoot":"","sources":["../../src/hooks/useAutoLock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"useAutoLock.js","sourceRoot":"","sources":["../../src/hooks/useAutoLock.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/hooks/useAutoLock.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
1
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
2
2
|
import { AppState as RNAppState, Platform } from "react-native";
|
|
3
3
|
|
|
4
4
|
const DEFAULT_IDLE_LOCK_MS = 10 * 60 * 1000;
|
|
@@ -18,14 +18,37 @@ export interface UseAutoLockOptions {
|
|
|
18
18
|
idleLockMs?: number;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
export interface UseAutoLockResult {
|
|
22
|
+
/**
|
|
23
|
+
* Call on any real user interaction to reset the idle clock. Required
|
|
24
|
+
* on native: unlike web (which listens on `window` for
|
|
25
|
+
* mousemove/touchstart/scroll/keydown directly), RN has no global
|
|
26
|
+
* "any touch happened anywhere" event — a touch inside a `Pressable`,
|
|
27
|
+
* `ScrollView`, etc. never reaches `window`, because there is no
|
|
28
|
+
* `window` to reach. Without a caller wiring this up (e.g. a capture-
|
|
29
|
+
* phase `onStartShouldSetResponderCapture` at the app root, returning
|
|
30
|
+
* `false` so it never actually claims the touch), the idle timer is
|
|
31
|
+
* armed once at mount and never reset — the session locks exactly
|
|
32
|
+
* `idleLockMs` after mount/foreground REGARDLESS of how actively the
|
|
33
|
+
* app is being used. Confirmed for real: a vault mid-active-use lost
|
|
34
|
+
* its key mid-session, and every item silently failed to decrypt
|
|
35
|
+
* (`Promise.allSettled` in the caller's list-fetch treats a decrypt
|
|
36
|
+
* failure as "drop this item", not "the vault relocked"), which reads
|
|
37
|
+
* to the user as vault items simply vanishing — no error, no visible
|
|
38
|
+
* cause, on 2026-08-17.
|
|
39
|
+
*/
|
|
40
|
+
notifyActivity: () => void;
|
|
41
|
+
}
|
|
42
|
+
|
|
21
43
|
/**
|
|
22
44
|
* Auto-lock a session after a period of inactivity. Generic over the
|
|
23
45
|
* lock predicate — vault wires `KeyManager.isUnlocked` / `KeyManager.lock`,
|
|
24
46
|
* other apps wire their own state. Web uses an idle-timer only; native
|
|
25
47
|
* additionally locks immediately when the app goes to the background.
|
|
26
48
|
*/
|
|
27
|
-
export function useAutoLock(options: UseAutoLockOptions):
|
|
49
|
+
export function useAutoLock(options: UseAutoLockOptions): UseAutoLockResult {
|
|
28
50
|
const { isUnlocked, onLock, isEnabled, idleLockMs = DEFAULT_IDLE_LOCK_MS } = options;
|
|
51
|
+
const onActivityRef = useRef<() => void>(() => {});
|
|
29
52
|
|
|
30
53
|
useEffect(() => {
|
|
31
54
|
let idleTimer: ReturnType<typeof setTimeout> | null = null;
|
|
@@ -64,6 +87,7 @@ export function useAutoLock(options: UseAutoLockOptions): void {
|
|
|
64
87
|
lastActivityAt = Date.now();
|
|
65
88
|
armIdleTimer();
|
|
66
89
|
};
|
|
90
|
+
onActivityRef.current = onActivity;
|
|
67
91
|
|
|
68
92
|
// On web, RN Web's AppState mirrors document visibility — tab-hidden
|
|
69
93
|
// becomes 'background', which would otherwise fire an immediate lock.
|
|
@@ -107,4 +131,10 @@ export function useAutoLock(options: UseAutoLockOptions): void {
|
|
|
107
131
|
};
|
|
108
132
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
109
133
|
}, []);
|
|
134
|
+
|
|
135
|
+
const notifyActivity = useCallback(() => {
|
|
136
|
+
onActivityRef.current();
|
|
137
|
+
}, []);
|
|
138
|
+
|
|
139
|
+
return { notifyActivity };
|
|
110
140
|
}
|