@qontinui/ui-bridge-native 0.4.0 → 0.6.1

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.
@@ -4,14 +4,33 @@
4
4
  * Register a native element with UI Bridge for control and observation.
5
5
  */
6
6
  import type { NativeElementType, NativeStandardAction, NativeCustomAction, NativeElementState, NativeElementIdentifier, RegisteredNativeElement, NativeElementRef } from '../core/types';
7
+ type AnyHandler = (...args: any[]) => any;
7
8
  /**
8
- * useUIElement options
9
+ * A press handler for `button`/`pressable` types. Matches the loose RN
10
+ * `Pressable` `onPress` shape (no required argument), so consumers can pass
11
+ * either a no-arg callback or one that consumes the gesture event.
9
12
  */
10
- export interface UseUIElementOptions {
13
+ export type PressHandler = (event?: unknown) => void;
14
+ /**
15
+ * Element types that require a press handler at registration. The TS
16
+ * signature on `useUIElement` rejects these types unless `handlers.onPress`
17
+ * is provided in options.
18
+ *
19
+ * Picked from the action-executor in `control/action-executor.ts` — the
20
+ * `press` action looks up `props.onPress` (or `onPressIn` /
21
+ * `onResponderRelease`); registering a button without one is a guaranteed
22
+ * dead-button per the 2026-05-20 manual-test session.
23
+ */
24
+ export type PressNeedingNativeElementType = 'button' | 'pressable';
25
+ /**
26
+ * Base options for `useUIElement`. The discriminated union below layers
27
+ * `handlers` requirements on top of this — see {@link UseUIElementOptions}.
28
+ */
29
+ export interface UseUIElementOptionsBase<T extends NativeElementType = NativeElementType> {
11
30
  /** Unique identifier for the element */
12
31
  id: string;
13
32
  /** Element type (defaults to 'custom') */
14
- type?: NativeElementType;
33
+ type?: T;
15
34
  /** Human-readable label */
16
35
  label?: string;
17
36
  /** Override available actions */
@@ -32,10 +51,24 @@ export interface UseUIElementOptions {
32
51
  focused?: unknown;
33
52
  disabled?: unknown;
34
53
  };
54
+ }
55
+ /**
56
+ * Options shape for press-needing types — `handlers.onPress` is REQUIRED.
57
+ * Registering a `button`/`pressable` without an `onPress` produces a
58
+ * "No press handler found on element" error when the bridge fires
59
+ * `POST /control/element/:id/action {"action":"press"}`. Phase 1 of plan
60
+ * `2026-05-20-manual-test-remediation` makes that a compile-time error.
61
+ *
62
+ * Consumers that wire `onPress` lazily (e.g. computed from props during
63
+ * render) should use {@link useUIElementWithProps} + `captureProps({ onPress })`
64
+ * instead. The runtime guard in this hook also warns once per id when
65
+ * `onPress` never reaches the registry.
66
+ */
67
+ export interface UseUIElementOptionsHandlersRequired<T extends PressNeedingNativeElementType = PressNeedingNativeElementType> extends UseUIElementOptionsBase<T> {
35
68
  /**
36
69
  * Handler props to auto-register with the bridge for action execution.
37
- * When provided, the bridge can invoke these handlers via press/type/toggle actions
38
- * without the component needing a separate useEffect + updateElementProps call.
70
+ * For `button`/`pressable`, `onPress` is required — UI Bridge invokes it
71
+ * when a `press` action is dispatched.
39
72
  *
40
73
  * @example
41
74
  * ```tsx
@@ -46,8 +79,32 @@ export interface UseUIElementOptions {
46
79
  * });
47
80
  * ```
48
81
  */
49
- handlers?: Record<string, ((...args: any[]) => any) | undefined>;
82
+ handlers: {
83
+ /** Required — UI Bridge invokes this on `press`/`click` actions. */
84
+ onPress: PressHandler;
85
+ /** Additional handlers (`onLongPress`, `onPressIn`, etc.) */
86
+ [key: string]: AnyHandler | undefined;
87
+ };
50
88
  }
89
+ /**
90
+ * Options shape for non-press-needing types — `handlers` is optional.
91
+ * Applies to `input`, `text`, `view`, `list`, etc. — anything where a
92
+ * missing `onPress` doesn't indicate a dead button.
93
+ */
94
+ export interface UseUIElementOptionsHandlersOptional<T extends NativeElementType = NativeElementType> extends UseUIElementOptionsBase<T> {
95
+ /**
96
+ * Handler props to auto-register with the bridge for action execution.
97
+ * Optional for non-press-needing types.
98
+ */
99
+ handlers?: Record<string, AnyHandler | undefined>;
100
+ }
101
+ /**
102
+ * useUIElement options — discriminated union over element type.
103
+ *
104
+ * For `type: 'button' | 'pressable'`, `handlers.onPress` is required.
105
+ * For all other types, `handlers` is optional.
106
+ */
107
+ export type UseUIElementOptions<T extends NativeElementType = NativeElementType> = T extends PressNeedingNativeElementType ? UseUIElementOptionsHandlersRequired<T> : UseUIElementOptionsHandlersOptional<T>;
51
108
  /**
52
109
  * Bridge props to spread onto the component
53
110
  */
@@ -97,34 +154,7 @@ export interface UseUIElementReturn {
97
154
  disabled?: unknown;
98
155
  }) => void;
99
156
  }
100
- /**
101
- * useUIElement hook for React Native
102
- *
103
- * Registers a native element with UI Bridge for programmatic control.
104
- *
105
- * @example
106
- * ```tsx
107
- * function SubmitButton() {
108
- * const { ref, onLayout, bridgeProps, trigger } = useUIElement({
109
- * id: 'submit-btn',
110
- * type: 'button',
111
- * label: 'Submit Form',
112
- * });
113
- *
114
- * return (
115
- * <Pressable
116
- * ref={ref}
117
- * onLayout={onLayout}
118
- * {...bridgeProps}
119
- * onPress={() => handleSubmit()}
120
- * >
121
- * <Text>Submit</Text>
122
- * </Pressable>
123
- * );
124
- * }
125
- * ```
126
- */
127
- export declare function useUIElement(options: UseUIElementOptions): UseUIElementReturn;
157
+ export declare function useUIElement<T extends NativeElementType = NativeElementType>(options: UseUIElementOptions<T>): UseUIElementReturn;
128
158
  /**
129
159
  * useUIElementWithProps hook
130
160
  *
@@ -158,5 +188,13 @@ export interface UseUIElementWithPropsReturn extends UseUIElementReturn {
158
188
  /** Capture props for action execution */
159
189
  captureProps: (props: Record<string, unknown>) => void;
160
190
  }
161
- export declare function useUIElementWithProps(options: UseUIElementOptions): UseUIElementWithPropsReturn;
191
+ /**
192
+ * Loose options for `useUIElementWithProps` — `handlers` is optional for ALL
193
+ * element types because the consumer will later call `captureProps({ onPress,
194
+ * ... })` from the render body. The runtime warning in {@link useUIElement}
195
+ * still backstops the "captured but never called with onPress" case.
196
+ */
197
+ export type UseUIElementWithPropsOptions<T extends NativeElementType = NativeElementType> = UseUIElementOptionsHandlersOptional<T>;
198
+ export declare function useUIElementWithProps<T extends NativeElementType = NativeElementType>(options: UseUIElementWithPropsOptions<T>): UseUIElementWithPropsReturn;
199
+ export {};
162
200
  //# sourceMappingURL=useUIElement.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useUIElement.d.ts","sourceRoot":"","sources":["../../src/react/useUIElement.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useUIElement.d.ts","sourceRoot":"","sources":["../../src/react/useUIElement.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/server/handlers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,sBAAsB,EAAuB,MAAM,kBAAkB,CAAC;AAQpF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAQV,oBAAoB,EAKrB,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AA+PhF;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,sBAAsB,EAChC,QAAQ,EAAE,oBAAoB,EAC9B,MAAM,CAAC,EAAE;IACP,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClF,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,iFAAiF;IACjF,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;CAC7C,GACA,oBAAoB,CAqvBtB"}
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/server/handlers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,sBAAsB,EAAuB,MAAM,kBAAkB,CAAC;AAQpF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,KAAK,EAQV,oBAAoB,EAKrB,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AA+PhF;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,sBAAsB,EAChC,QAAQ,EAAE,oBAAoB,EAC9B,MAAM,CAAC,EAAE;IACP,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClF,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,iFAAiF;IACjF,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;CAC7C,GACA,oBAAoB,CAkzBtB"}
@@ -12,7 +12,7 @@
12
12
  */
13
13
  import type { NativeUIBridgeRegistry } from '../core/registry';
14
14
  import type { NativeActionExecutor } from '../control/types';
15
- import type { NativeServerConfig, NavigationProvider, RouteProvider, ScreenshotProvider } from './types';
15
+ import type { NativeServerConfig, NavigationProvider, RouteProvider, ScreenshotProvider, KeepAwakeProvider } from './types';
16
16
  import type { WebSocketEventBridge } from './ws-event-bridge';
17
17
  import type { JsonRpcRequest, JsonRpcResponse } from './ws-types';
18
18
  /**
@@ -79,6 +79,7 @@ export declare class NativeUIBridgeServer {
79
79
  private handlers;
80
80
  private adapter?;
81
81
  private running;
82
+ private keepAwakeProvider?;
82
83
  /**
83
84
  * Per-connection cleanup thunks for in-flight waiters (waitForElement,
84
85
  * waitForCondition, ...). Aborted when a client disconnects so the
@@ -120,6 +121,12 @@ export declare class NativeUIBridgeServer {
120
121
  * This enables `control/screenshot` on native.
121
122
  */
122
123
  setScreenshotProvider(provider: ScreenshotProvider): void;
124
+ /**
125
+ * Set a keep-awake provider for native screen-wake control.
126
+ * This enables `control/keep-awake` and arms the auto-arm hook in
127
+ * handleRequest (every request keeps the screen alive for 60s).
128
+ */
129
+ setKeepAwakeProvider(provider: KeepAwakeProvider): void;
123
130
  /**
124
131
  * Start the HTTP server
125
132
  */
@@ -1 +1 @@
1
- {"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../../src/server/http-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../../src/server/http-server.ts"],"names":[],"mappings":"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"}
@@ -141,6 +141,31 @@ var UI_BRIDGE_NATIVE_ROUTES = {
141
141
  path: "/ui-bridge/ai/fill-form",
142
142
  description: "Fill multiple input elements in a single call"
143
143
  },
144
+ // AI helpers (NOT_SUPPORTED stubs) — these endpoints exist on the runner-side
145
+ // UI Bridge surface but have no analog on mobile React Native. The mobile
146
+ // bridge registers explicit stubs so callers get a structured NOT_SUPPORTED
147
+ // envelope instead of a confusing HTTP 404. The mobile bridge's snapshot +
148
+ // `/control/find` already cover what an operator would reach for these for.
149
+ AI_FORMS: {
150
+ method: "GET",
151
+ path: "/ui-bridge/ai/forms",
152
+ description: "Discover forms (runner-only; mobile returns NOT_SUPPORTED)"
153
+ },
154
+ AI_IDLE_STATUS: {
155
+ method: "GET",
156
+ path: "/ui-bridge/ai/idle-status",
157
+ description: "Get page-idle signal (runner-only; mobile returns NOT_SUPPORTED)"
158
+ },
159
+ AI_CHANGE_BUFFER_ENABLE: {
160
+ method: "POST",
161
+ path: "/ui-bridge/ai/change-buffer/enable",
162
+ description: "Enable DOM change buffer (runner-only; mobile returns NOT_SUPPORTED)"
163
+ },
164
+ AI_WAIT_FOR_ELEMENT: {
165
+ method: "POST",
166
+ path: "/ui-bridge/ai/wait-for-element",
167
+ description: "Wait for element predicate via HTTP (runner-only; mobile returns NOT_SUPPORTED \u2014 use WS waitForElement instead)"
168
+ },
144
169
  // Test hooks — drive ModalDetector state from outside the React tree
145
170
  // (gated by `features.testHooks`). Mirrors `pushModal` / `dismissModal`
146
171
  // calls that components normally make in-process.
@@ -847,22 +872,25 @@ function createServerHandlers(registry, executor, config) {
847
872
  getElements: async (ctx) => {
848
873
  const visibleOnly = ctx.query?.visibleOnly === "true" || ctx.body?.visibleOnly === true;
849
874
  const forRoute = ctx.query?.route || ctx.body?.route;
850
- let allElements = visibleOnly ? registry.getVisibleElements() : registry.getAllElements();
875
+ let allElements = visibleOnly ? registry.getMountedVisibleElements() : registry.getAllElements();
851
876
  if (forRoute) {
852
877
  allElements = allElements.filter((e) => e.registrationRoute === forRoute);
853
878
  }
854
879
  const elements = allElements.map((e) => {
855
880
  const handlers = extractHandlerNames(e.props);
881
+ const state = e.getState();
882
+ const visibility = !state.visible ? "hidden" : state.layout !== null ? "visible" : "likely-visible";
856
883
  return {
857
884
  id: e.id,
858
885
  type: e.type,
859
886
  label: e.label,
860
887
  identifier: e.getIdentifier(),
861
- state: e.getState(),
888
+ state,
862
889
  actions: e.actions,
863
890
  customActions: e.customActions ? Object.keys(e.customActions) : void 0,
864
891
  registeredHandlers: handlers.length > 0 ? handlers : void 0,
865
- registrationRoute: e.registrationRoute
892
+ registrationRoute: e.registrationRoute,
893
+ visibility
866
894
  };
867
895
  });
868
896
  return success2({ elements });
@@ -1117,6 +1145,45 @@ function createServerHandlers(registry, executor, config) {
1117
1145
  "NOT_SUPPORTED"
1118
1146
  );
1119
1147
  },
1148
+ // Keep-awake (stub — apps should override via setKeepAwakeProvider, which
1149
+ // the provider wires when a keepAwakeProvider prop is supplied)
1150
+ keepAwake: async () => {
1151
+ return error2(
1152
+ "keep-awake not configured. Provide a keepAwakeProvider to UIBridgeNativeProvider.",
1153
+ "NOT_SUPPORTED"
1154
+ );
1155
+ },
1156
+ // AI helpers — runner-only endpoints that have no React Native analog.
1157
+ //
1158
+ // The mobile bridge mounts explicit NOT_SUPPORTED stubs at the runner's
1159
+ // cheatsheet paths so callers (and the /manual-test skill in particular)
1160
+ // get a structured envelope explaining the gap rather than a confusing
1161
+ // HTTP 404. Each error message names an in-tree mobile replacement so
1162
+ // operators aren't left guessing what to use instead.
1163
+ aiForms: async () => {
1164
+ return error2(
1165
+ 'ai/forms (form discovery) is runner-only; mobile React Native has no DOM to walk. Use GET /ui-bridge/control/snapshot and filter for type === "input" instead.',
1166
+ "NOT_SUPPORTED"
1167
+ );
1168
+ },
1169
+ aiIdleStatus: async () => {
1170
+ return error2(
1171
+ 'ai/idle-status (page-idle signal) is runner-only; mobile React Native has no DOM-mutation / network-idle signals. Use the registry event stream (WS subscribe to "element:registered"/"element:stateChanged") or poll /control/snapshot for stability.',
1172
+ "NOT_SUPPORTED"
1173
+ );
1174
+ },
1175
+ aiChangeBufferEnable: async () => {
1176
+ return error2(
1177
+ 'ai/change-buffer (DOM mutation diff buffer) is runner-only; mobile React Native has no DOM. Use the WS event bridge (subscribe to "element:registered"/"element:unregistered"/"element:stateChanged") for change notifications.',
1178
+ "NOT_SUPPORTED"
1179
+ );
1180
+ },
1181
+ aiWaitForElement: async () => {
1182
+ return error2(
1183
+ 'POST /ai/wait-for-element is runner-only on mobile. Use the WS "waitForElement" JSON-RPC method or "waitForCondition" instead \u2014 same semantics, no HTTP polling overhead.',
1184
+ "NOT_SUPPORTED"
1185
+ );
1186
+ },
1120
1187
  // Meta / Introspection (stub — server constructor overrides with real route table)
1121
1188
  getMethods: async () => {
1122
1189
  return error2("Methods introspection not configured", "NOT_SUPPORTED");
@@ -1772,6 +1839,24 @@ var WS_ROUTES = [
1772
1839
  { pattern: "meta/methods", handler: "getMethods", httpMethods: ["GET"] },
1773
1840
  // AI helpers — mobile parity with the runner's `/ui-bridge/ai/*` family.
1774
1841
  { pattern: "ai/fill-form", handler: "fillForm", httpMethods: ["POST"] },
1842
+ // AI helpers — NOT_SUPPORTED stubs. These endpoints exist on the runner-side
1843
+ // UI Bridge surface (and the /manual-test skill's cheatsheet documents them
1844
+ // as if they're universally available). Mobile React Native has no DOM, so
1845
+ // the mobile bridge mounts explicit stubs so callers get a structured
1846
+ // NOT_SUPPORTED envelope (with a hint pointing at the mobile-native
1847
+ // replacement) instead of a confusing HTTP 404.
1848
+ { pattern: "ai/forms", handler: "aiForms", httpMethods: ["GET"] },
1849
+ { pattern: "ai/idle-status", handler: "aiIdleStatus", httpMethods: ["GET"] },
1850
+ {
1851
+ pattern: "ai/change-buffer/enable",
1852
+ handler: "aiChangeBufferEnable",
1853
+ httpMethods: ["POST"]
1854
+ },
1855
+ {
1856
+ pattern: "ai/wait-for-element",
1857
+ handler: "aiWaitForElement",
1858
+ httpMethods: ["POST"]
1859
+ },
1775
1860
  // Coord-based tap — synthesizes a press at the given screen coords by
1776
1861
  // matching against registered elements' layout rects.
1777
1862
  { pattern: "control/tap", handler: "tapAt", httpMethods: ["POST"] },
@@ -1790,6 +1875,12 @@ var WS_ROUTES = [
1790
1875
  httpMethods: ["POST"],
1791
1876
  requiresTestHooks: true
1792
1877
  },
1878
+ {
1879
+ pattern: "control/keep-awake",
1880
+ handler: "keepAwake",
1881
+ httpMethods: ["POST"],
1882
+ requiresTestHooks: true
1883
+ },
1793
1884
  // Observability — last-N console errors + network requests. testHooks-gated
1794
1885
  // because patching `console.error` / `fetch` is invasive in production.
1795
1886
  {
@@ -1838,11 +1929,16 @@ var HANDLER_DESCRIPTIONS = {
1838
1929
  diffBaseline: "Diff current UI against a saved baseline",
1839
1930
  getMethods: "List every handler name (legacy introspection)",
1840
1931
  fillForm: "Fill multiple inputs in one call: body { fields: [{elementId, value}] } \u2014 each field dispatches `type` + `clear:true`",
1932
+ aiForms: 'STUB \u2014 runner-only; mobile returns NOT_SUPPORTED. Use /control/snapshot + filter type==="input" instead.',
1933
+ aiIdleStatus: "STUB \u2014 runner-only; mobile returns NOT_SUPPORTED. Subscribe to registry events over WS for change signals.",
1934
+ aiChangeBufferEnable: "STUB \u2014 runner-only; mobile returns NOT_SUPPORTED. Use WS event subscriptions for change notifications.",
1935
+ aiWaitForElement: "STUB \u2014 runner-only; mobile returns NOT_SUPPORTED. Use the WS waitForElement / waitForCondition JSON-RPC methods.",
1841
1936
  tapAt: "Synthesize a press at given screen coords by matching registered element layout rects: body { x, y, action? }",
1842
1937
  getConsoleErrors: "TEST HOOK \u2014 last-N console.error/console.warn entries; ?since=<ms>&limit=<n>",
1843
1938
  getNetworkRequests: "TEST HOOK \u2014 last-N fetch/XHR entries with status + duration; ?since=<ms>&limit=<n>",
1844
1939
  pushModal: "TEST HOOK \u2014 push a modal onto the snapshot.modalStack via the registry ModalDetector",
1845
- dismissModal: "TEST HOOK \u2014 dismiss a modal by id from the snapshot.modalStack via the registry ModalDetector"
1940
+ dismissModal: "TEST HOOK \u2014 dismiss a modal by id from the snapshot.modalStack via the registry ModalDetector",
1941
+ keepAwake: "TEST HOOK \u2014 keep the device screen awake via the injected keepAwakeProvider: body { enabled: boolean, durationMs?: number }"
1846
1942
  };
1847
1943
  var ACTION_REFERENCE = [
1848
1944
  { name: "press", aliases: ["click"], params: "PressActionParams (optional position)" },
@@ -2110,6 +2206,35 @@ var NativeUIBridgeServer = class {
2110
2206
  }
2111
2207
  };
2112
2208
  }
2209
+ /**
2210
+ * Set a keep-awake provider for native screen-wake control.
2211
+ * This enables `control/keep-awake` and arms the auto-arm hook in
2212
+ * handleRequest (every request keeps the screen alive for 60s).
2213
+ */
2214
+ setKeepAwakeProvider(provider) {
2215
+ this.keepAwakeProvider = provider;
2216
+ this.handlers.keepAwake = async (ctx) => {
2217
+ const { enabled, durationMs } = ctx.body ?? {};
2218
+ if (typeof enabled !== "boolean") {
2219
+ return {
2220
+ success: false,
2221
+ error: "enabled must be boolean",
2222
+ code: "INVALID_REQUEST",
2223
+ timestamp: Date.now()
2224
+ };
2225
+ }
2226
+ if (enabled) {
2227
+ provider.request("ui-bridge", typeof durationMs === "number" ? durationMs : void 0);
2228
+ } else {
2229
+ provider.release("ui-bridge");
2230
+ }
2231
+ return {
2232
+ success: true,
2233
+ data: { enabled, durationMs: typeof durationMs === "number" ? durationMs : null },
2234
+ timestamp: Date.now()
2235
+ };
2236
+ };
2237
+ }
2113
2238
  /**
2114
2239
  * Start the HTTP server
2115
2240
  */
@@ -2702,6 +2827,12 @@ var NativeUIBridgeServer = class {
2702
2827
  if (request.method === "OPTIONS") {
2703
2828
  return { status: 204, headers, body: "" };
2704
2829
  }
2830
+ if (this.config.testHooks === true && this.keepAwakeProvider) {
2831
+ try {
2832
+ this.keepAwakeProvider.request("auto-arm", 6e4);
2833
+ } catch {
2834
+ }
2835
+ }
2705
2836
  try {
2706
2837
  const response = await this.routeRequest(request);
2707
2838
  return {