@entropy-softworks/ui 2026.9.5 → 2026.9.6

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.
@@ -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,MAAM,WAAW,iBAAiB;IAChC;;;;;;;;;;;;;;;;;OAiBG;IACH,cAAc,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,CAuH1E"}
1
+ {"version":3,"file":"useAutoLock.d.ts","sourceRoot":"","sources":["../../src/hooks/useAutoLock.ts"],"names":[],"mappings":"AAUA,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,CAqJ1E"}
@@ -1,6 +1,10 @@
1
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
+ /** How often the suspend detector below checks in. */
5
+ const HEARTBEAT_MS = 1000;
6
+ /** A gap this large between checks means the app was not running. */
7
+ const SUSPEND_GAP_MS = 4000;
4
8
  /**
5
9
  * Auto-lock a session after a period of inactivity. Generic over the
6
10
  * lock predicate — vault wires `KeyManager.isUnlocked` / `KeyManager.lock`,
@@ -83,6 +87,34 @@ export function useAutoLock(options) {
83
87
  armIdleTimer();
84
88
  }
85
89
  });
90
+ /**
91
+ * The backstop that does not involve AppState at all.
92
+ *
93
+ * AppState was the only way this hook knew the app had gone away, and on a
94
+ * real device it was reported not firing for either a minimise or a screen
95
+ * lock — the vault was still open on return, with the setting on. Rather
96
+ * than keep guessing which event a given platform version emits, this
97
+ * measures the thing that actually matters: a suspended app's timers stop.
98
+ *
99
+ * The interval ticks every second. If more than `SUSPEND_GAP_MS` of wall
100
+ * clock passed since the last tick, the app was not running, whatever the
101
+ * OS did or did not tell us — so lock.
102
+ *
103
+ * The threshold is well above any plausible stall on the JS thread, which
104
+ * is the one other thing that can delay an interval. Four seconds is far
105
+ * more than the heaviest work this app does in one go (opening a vault is
106
+ * milliseconds now that the crypto is native) and still short enough that
107
+ * putting a phone down and picking it up again lands on a locked vault.
108
+ */
109
+ let lastTick = Date.now();
110
+ const heartbeat = setInterval(() => {
111
+ const now = Date.now();
112
+ const gap = now - lastTick;
113
+ lastTick = now;
114
+ if (Platform.OS !== "web" && gap > SUSPEND_GAP_MS) {
115
+ lockIfEnabled();
116
+ }
117
+ }, HEARTBEAT_MS);
86
118
  const cleanups = [];
87
119
  if (Platform.OS === "web" && typeof document !== "undefined") {
88
120
  const onVisibility = () => {
@@ -101,6 +133,7 @@ export function useAutoLock(options) {
101
133
  armIdleTimer();
102
134
  return () => {
103
135
  subscription.remove();
136
+ clearInterval(heartbeat);
104
137
  for (const fn of cleanups) {
105
138
  fn();
106
139
  }
@@ -1 +1 @@
1
- {"version":3,"file":"useAutoLock.js","sourceRoot":"","sources":["../../src/hooks/useAutoLock.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useAutoLock.js","sourceRoot":"","sources":["../../src/hooks/useAutoLock.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@entropy-softworks/ui",
3
- "version": "2026.9.5",
3
+ "version": "2026.9.6",
4
4
  "private": false,
5
5
  "description": "Shared React Native UI primitives, auth screens, hooks, and services for Entropy Softworks Expo apps",
6
6
  "license": "MIT",
@@ -3,6 +3,11 @@ import { AppState as RNAppState, Platform } from "react-native";
3
3
 
4
4
  const DEFAULT_IDLE_LOCK_MS = 10 * 60 * 1000;
5
5
 
6
+ /** How often the suspend detector below checks in. */
7
+ const HEARTBEAT_MS = 1000;
8
+ /** A gap this large between checks means the app was not running. */
9
+ const SUSPEND_GAP_MS = 4000;
10
+
6
11
  export interface UseAutoLockOptions {
7
12
  /**
8
13
  * Reports whether the session is currently "unlocked" (vault-style
@@ -128,6 +133,35 @@ export function useAutoLock(options: UseAutoLockOptions): UseAutoLockResult {
128
133
  }
129
134
  });
130
135
 
136
+ /**
137
+ * The backstop that does not involve AppState at all.
138
+ *
139
+ * AppState was the only way this hook knew the app had gone away, and on a
140
+ * real device it was reported not firing for either a minimise or a screen
141
+ * lock — the vault was still open on return, with the setting on. Rather
142
+ * than keep guessing which event a given platform version emits, this
143
+ * measures the thing that actually matters: a suspended app's timers stop.
144
+ *
145
+ * The interval ticks every second. If more than `SUSPEND_GAP_MS` of wall
146
+ * clock passed since the last tick, the app was not running, whatever the
147
+ * OS did or did not tell us — so lock.
148
+ *
149
+ * The threshold is well above any plausible stall on the JS thread, which
150
+ * is the one other thing that can delay an interval. Four seconds is far
151
+ * more than the heaviest work this app does in one go (opening a vault is
152
+ * milliseconds now that the crypto is native) and still short enough that
153
+ * putting a phone down and picking it up again lands on a locked vault.
154
+ */
155
+ let lastTick = Date.now();
156
+ const heartbeat = setInterval(() => {
157
+ const now = Date.now();
158
+ const gap = now - lastTick;
159
+ lastTick = now;
160
+ if (Platform.OS !== "web" && gap > SUSPEND_GAP_MS) {
161
+ lockIfEnabled();
162
+ }
163
+ }, HEARTBEAT_MS);
164
+
131
165
  const cleanups: (() => void)[] = [];
132
166
 
133
167
  if (Platform.OS === "web" && typeof document !== "undefined") {
@@ -150,6 +184,7 @@ export function useAutoLock(options: UseAutoLockOptions): UseAutoLockResult {
150
184
 
151
185
  return () => {
152
186
  subscription.remove();
187
+ clearInterval(heartbeat);
153
188
  for (const fn of cleanups) {
154
189
  fn();
155
190
  }