@qontinui/ui-bridge-native 0.6.8 → 0.6.10
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/dist/control/action-executor.d.ts +15 -0
- package/dist/control/action-executor.d.ts.map +1 -1
- package/dist/control/index.js +36 -1
- package/dist/control/index.js.map +1 -1
- package/dist/control/index.mjs +36 -1
- package/dist/control/index.mjs.map +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +1 -1
- package/dist/core/index.mjs.map +1 -1
- package/dist/core/types.d.ts +1 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +153 -26
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +152 -27
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.js +94 -26
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +94 -26
- package/dist/react/index.mjs.map +1 -1
- package/dist/react/useUIElement.d.ts +10 -0
- package/dist/react/useUIElement.d.ts.map +1 -1
- package/dist/server/bind-retry.d.ts +64 -0
- package/dist/server/bind-retry.d.ts.map +1 -0
- package/dist/server/handlers.d.ts.map +1 -1
- package/dist/server/http-server.d.ts.map +1 -1
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +103 -22
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +102 -23
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/types.d.ts +14 -0
- package/dist/server/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/server/index.mjs
CHANGED
|
@@ -55,6 +55,11 @@ var UI_BRIDGE_NATIVE_ROUTES = {
|
|
|
55
55
|
path: "/ui-bridge/control/snapshot",
|
|
56
56
|
description: "Get full bridge snapshot"
|
|
57
57
|
},
|
|
58
|
+
DISCOVER: {
|
|
59
|
+
method: "GET",
|
|
60
|
+
path: "/ui-bridge/control/discover",
|
|
61
|
+
description: "Discover elements (alias for snapshot; web/runner parity)"
|
|
62
|
+
},
|
|
58
63
|
PAGE_HEALTH: {
|
|
59
64
|
method: "POST",
|
|
60
65
|
path: "/ui-bridge/control/page-health",
|
|
@@ -182,6 +187,18 @@ var UI_BRIDGE_NATIVE_ROUTES = {
|
|
|
182
187
|
path: "/ui-bridge/control/modal/dismiss/:id",
|
|
183
188
|
description: "Dismiss a modal by id (testHooks)"
|
|
184
189
|
},
|
|
190
|
+
// Observability — last-N ring buffers (always mounted; `installed:false`
|
|
191
|
+
// when the console/network patches are off, i.e. no testHooks).
|
|
192
|
+
CONSOLE_ERRORS: {
|
|
193
|
+
method: "GET",
|
|
194
|
+
path: "/ui-bridge/control/console-errors",
|
|
195
|
+
description: "Last-N captured console.error/console.warn entries"
|
|
196
|
+
},
|
|
197
|
+
NETWORK_REQUESTS: {
|
|
198
|
+
method: "GET",
|
|
199
|
+
path: "/ui-bridge/sdk/network-requests",
|
|
200
|
+
description: "Last-N captured fetch/XHR requests with status + duration"
|
|
201
|
+
},
|
|
185
202
|
// Health
|
|
186
203
|
HEALTH: {
|
|
187
204
|
method: "GET",
|
|
@@ -941,6 +958,13 @@ function matchElementsByText(registry, text, opts) {
|
|
|
941
958
|
scored.sort((a, b) => a.rank - b.rank);
|
|
942
959
|
return scored.map((s) => s.element);
|
|
943
960
|
}
|
|
961
|
+
function resolveElementState(element) {
|
|
962
|
+
const state = element.getState();
|
|
963
|
+
if (element.type === "input" && state.value === void 0 && typeof element.props?.value === "string") {
|
|
964
|
+
return { ...state, value: element.props.value };
|
|
965
|
+
}
|
|
966
|
+
return state;
|
|
967
|
+
}
|
|
944
968
|
async function executeWorkflowStep(step, registry, executor) {
|
|
945
969
|
const startTime = Date.now();
|
|
946
970
|
try {
|
|
@@ -1177,7 +1201,7 @@ function createServerHandlers(registry, executor, config) {
|
|
|
1177
1201
|
type: element.type,
|
|
1178
1202
|
label: element.label,
|
|
1179
1203
|
identifier: element.getIdentifier(),
|
|
1180
|
-
state: element
|
|
1204
|
+
state: resolveElementState(element),
|
|
1181
1205
|
actions: element.actions,
|
|
1182
1206
|
customActions: element.customActions ? Object.keys(element.customActions) : void 0,
|
|
1183
1207
|
registeredHandlers: handlers.length > 0 ? handlers : void 0,
|
|
@@ -1191,18 +1215,19 @@ function createServerHandlers(registry, executor, config) {
|
|
|
1191
1215
|
if (!element) {
|
|
1192
1216
|
return error2(`Element not found: ${id}`, "ELEMENT_NOT_FOUND");
|
|
1193
1217
|
}
|
|
1194
|
-
return success2({ state: element
|
|
1218
|
+
return success2({ state: resolveElementState(element) });
|
|
1195
1219
|
},
|
|
1196
1220
|
executeAction: async (ctx) => {
|
|
1197
|
-
const
|
|
1198
|
-
const
|
|
1199
|
-
|
|
1221
|
+
const rawBody = ctx.body ?? {};
|
|
1222
|
+
const envelope = rawBody.request && typeof rawBody.request === "object" ? rawBody.request : rawBody;
|
|
1223
|
+
const id = ctx.params.id ?? rawBody.id ?? "";
|
|
1224
|
+
if (!envelope?.action) {
|
|
1200
1225
|
return error2("Action is required", "INVALID_REQUEST");
|
|
1201
1226
|
}
|
|
1202
1227
|
const response = await executor.executeAction(id, {
|
|
1203
|
-
action:
|
|
1204
|
-
params:
|
|
1205
|
-
waitOptions:
|
|
1228
|
+
action: envelope.action,
|
|
1229
|
+
params: envelope.params,
|
|
1230
|
+
waitOptions: envelope.waitOptions
|
|
1206
1231
|
});
|
|
1207
1232
|
if (!response.success) {
|
|
1208
1233
|
return error2(response.error || "Action failed", "ACTION_FAILED");
|
|
@@ -1714,7 +1739,8 @@ function createServerHandlers(registry, executor, config) {
|
|
|
1714
1739
|
return success2({
|
|
1715
1740
|
entries: [],
|
|
1716
1741
|
count: 0,
|
|
1717
|
-
bufferSize: 0
|
|
1742
|
+
bufferSize: 0,
|
|
1743
|
+
installed: false
|
|
1718
1744
|
});
|
|
1719
1745
|
}
|
|
1720
1746
|
const entries = buf.entries({
|
|
@@ -1724,7 +1750,8 @@ function createServerHandlers(registry, executor, config) {
|
|
|
1724
1750
|
return success2({
|
|
1725
1751
|
entries,
|
|
1726
1752
|
count: entries.length,
|
|
1727
|
-
bufferSize: buf.size()
|
|
1753
|
+
bufferSize: buf.size(),
|
|
1754
|
+
installed: buf.isInstalled()
|
|
1728
1755
|
});
|
|
1729
1756
|
},
|
|
1730
1757
|
getNetworkRequests: async (ctx) => {
|
|
@@ -1735,7 +1762,8 @@ function createServerHandlers(registry, executor, config) {
|
|
|
1735
1762
|
return success2({
|
|
1736
1763
|
entries: [],
|
|
1737
1764
|
count: 0,
|
|
1738
|
-
bufferSize: 0
|
|
1765
|
+
bufferSize: 0,
|
|
1766
|
+
installed: false
|
|
1739
1767
|
});
|
|
1740
1768
|
}
|
|
1741
1769
|
const entries = buf.entries({
|
|
@@ -1745,7 +1773,8 @@ function createServerHandlers(registry, executor, config) {
|
|
|
1745
1773
|
return success2({
|
|
1746
1774
|
entries,
|
|
1747
1775
|
count: entries.length,
|
|
1748
|
-
bufferSize: buf.size()
|
|
1776
|
+
bufferSize: buf.size(),
|
|
1777
|
+
installed: buf.isInstalled()
|
|
1749
1778
|
});
|
|
1750
1779
|
},
|
|
1751
1780
|
// Test hooks — modal stack manipulation
|
|
@@ -1837,7 +1866,7 @@ function createServerHandlers(registry, executor, config) {
|
|
|
1837
1866
|
};
|
|
1838
1867
|
if (config?.appInfo) {
|
|
1839
1868
|
response.uiBridge = {
|
|
1840
|
-
version: "0.
|
|
1869
|
+
version: "0.6.10",
|
|
1841
1870
|
...config.appInfo,
|
|
1842
1871
|
capabilities: ["elements", "components", "actions", "design"],
|
|
1843
1872
|
elementCount: stats.elements,
|
|
@@ -2164,7 +2193,10 @@ var WS_ROUTES = [
|
|
|
2164
2193
|
// same handler at both paths to keep agents portable across platforms.
|
|
2165
2194
|
{ pattern: "ai/find", handler: "find", httpMethods: ["POST"] },
|
|
2166
2195
|
{ pattern: "control/snapshot", handler: "getSnapshot", httpMethods: ["GET"] },
|
|
2167
|
-
|
|
2196
|
+
// Discovery alias — web/runner parity with `POST /control/discover` (a
|
|
2197
|
+
// legacy alias for snapshot/find). Mounted on HTTP (GET+POST) so mobile
|
|
2198
|
+
// doesn't 404 where web returns 200; delegates to the snapshot handler.
|
|
2199
|
+
{ pattern: "control/discover", handler: "getSnapshot", httpMethods: ["GET", "POST"] },
|
|
2168
2200
|
// Page health — accepts both GET and POST so the canonical skill invocation
|
|
2169
2201
|
// (`POST .../control/page-health` with an empty body) and ad-hoc curls both
|
|
2170
2202
|
// work without a body-shape gotcha.
|
|
@@ -2258,19 +2290,26 @@ var WS_ROUTES = [
|
|
|
2258
2290
|
httpMethods: ["POST"],
|
|
2259
2291
|
requiresTestHooks: true
|
|
2260
2292
|
},
|
|
2261
|
-
// Observability — last-N console errors + network requests.
|
|
2262
|
-
//
|
|
2293
|
+
// Observability — last-N console errors + network requests.
|
|
2294
|
+
//
|
|
2295
|
+
// Always mounted (not testHooks-gated) so they return a schema-valid 200
|
|
2296
|
+
// on every build instead of a 404 that agents can't distinguish from a
|
|
2297
|
+
// missing route. The INVASIVE part — monkey-patching `console.error` /
|
|
2298
|
+
// `fetch` / `XMLHttpRequest` — stays gated behind `testHooks` (see
|
|
2299
|
+
// NativeUIBridgeServer.start → buffer.install()). When the patches aren't
|
|
2300
|
+
// installed the handlers report `installed: false` + empty entries, so
|
|
2301
|
+
// production builds expose the contract without observing real users'
|
|
2302
|
+
// console/network traffic. Set `features.testHooks` (typically on
|
|
2303
|
+
// `__DEV__`) to populate the buffers with live data.
|
|
2263
2304
|
{
|
|
2264
2305
|
pattern: "control/console-errors",
|
|
2265
2306
|
handler: "getConsoleErrors",
|
|
2266
|
-
httpMethods: ["GET"]
|
|
2267
|
-
requiresTestHooks: true
|
|
2307
|
+
httpMethods: ["GET"]
|
|
2268
2308
|
},
|
|
2269
2309
|
{
|
|
2270
2310
|
pattern: "sdk/network-requests",
|
|
2271
2311
|
handler: "getNetworkRequests",
|
|
2272
|
-
httpMethods: ["GET"]
|
|
2273
|
-
requiresTestHooks: true
|
|
2312
|
+
httpMethods: ["GET"]
|
|
2274
2313
|
}
|
|
2275
2314
|
];
|
|
2276
2315
|
var HANDLER_DESCRIPTIONS = {
|
|
@@ -2317,8 +2356,8 @@ var HANDLER_DESCRIPTIONS = {
|
|
|
2317
2356
|
typeInto: "App-agnostic: type into the input matching a label: body { label, text, clear?, visibleOnly? }. (selector form is web-only)",
|
|
2318
2357
|
readValue: "STUB \u2014 selector-based; NOT_SUPPORTED on native (no DOM). Use /control/element/:id/state to read a value.",
|
|
2319
2358
|
findByText: "App-agnostic: list elements matching free-text (no press): body { text, visibleOnly? }",
|
|
2320
|
-
getConsoleErrors: "
|
|
2321
|
-
getNetworkRequests: "
|
|
2359
|
+
getConsoleErrors: "Last-N console.error/console.warn entries; ?since=<ms>&limit=<n>. `installed:false` when capture is off (no testHooks) \u2014 entries empty but schema-valid.",
|
|
2360
|
+
getNetworkRequests: "Last-N fetch/XHR entries with status + duration; ?since=<ms>&limit=<n>. `installed:false` when capture is off (no testHooks) \u2014 entries empty but schema-valid.",
|
|
2322
2361
|
pushModal: "TEST HOOK \u2014 push a modal onto the snapshot.modalStack via the registry ModalDetector",
|
|
2323
2362
|
dismissModal: "TEST HOOK \u2014 dismiss a modal by id from the snapshot.modalStack via the registry ModalDetector",
|
|
2324
2363
|
keepAwake: "TEST HOOK \u2014 keep the device screen awake via the injected keepAwakeProvider: body { enabled: boolean, durationMs?: number }"
|
|
@@ -3953,6 +3992,46 @@ var WebSocketConnection = class {
|
|
|
3953
3992
|
}
|
|
3954
3993
|
};
|
|
3955
3994
|
|
|
3956
|
-
|
|
3995
|
+
// src/server/bind-retry.ts
|
|
3996
|
+
function isAddrInUseError(err) {
|
|
3997
|
+
const message = err instanceof Error ? err.message : typeof err === "string" ? err : String(err);
|
|
3998
|
+
const code = err?.code;
|
|
3999
|
+
return message.includes("EADDRINUSE") || message.toLowerCase().includes("address already in use") || code === "EADDRINUSE";
|
|
4000
|
+
}
|
|
4001
|
+
var defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
4002
|
+
async function bindWithRetry(attempt, options = {}) {
|
|
4003
|
+
const {
|
|
4004
|
+
minTotalMs = 3e4,
|
|
4005
|
+
initialDelayMs = 500,
|
|
4006
|
+
maxDelayMs = 5e3,
|
|
4007
|
+
backoffFactor = 2,
|
|
4008
|
+
logger = console,
|
|
4009
|
+
sleep = defaultSleep,
|
|
4010
|
+
now = Date.now
|
|
4011
|
+
} = options;
|
|
4012
|
+
const startedAt = now();
|
|
4013
|
+
let delay = initialDelayMs;
|
|
4014
|
+
let attemptIndex = 0;
|
|
4015
|
+
for (; ; ) {
|
|
4016
|
+
try {
|
|
4017
|
+
await attempt(attemptIndex);
|
|
4018
|
+
return;
|
|
4019
|
+
} catch (err) {
|
|
4020
|
+
const elapsed = now() - startedAt;
|
|
4021
|
+
const budgetExhausted = elapsed + delay >= minTotalMs;
|
|
4022
|
+
if (!isAddrInUseError(err) || budgetExhausted) {
|
|
4023
|
+
throw err;
|
|
4024
|
+
}
|
|
4025
|
+
logger.warn(
|
|
4026
|
+
`[ui-bridge-native] bind failed with EADDRINUSE (attempt ${attemptIndex + 1}); retrying in ${delay}ms (elapsed ${elapsed}ms / budget ${minTotalMs === Infinity ? "\u221E" : minTotalMs}ms)`
|
|
4027
|
+
);
|
|
4028
|
+
await sleep(delay);
|
|
4029
|
+
delay = Math.min(delay * backoffFactor, maxDelayMs);
|
|
4030
|
+
attemptIndex += 1;
|
|
4031
|
+
}
|
|
4032
|
+
}
|
|
4033
|
+
}
|
|
4034
|
+
|
|
4035
|
+
export { ConsoleErrorBuffer, NativeUIBridgeServer, NetworkRequestBuffer, OPCODE_BINARY, OPCODE_CLOSE, OPCODE_CONTINUATION, OPCODE_PING, OPCODE_PONG, OPCODE_TEXT, UI_BRIDGE_NATIVE_ROUTES, WebSocketConnection, WebSocketEventBridge, bindWithRetry, buildUpgradeResponse, computeAcceptKey, createDesignHandlers, createNativeServer, createServerHandlers, decodeFrames, decodeTextPayload, encodeCloseFrame, encodePingFrame, encodePongFrame, encodeTextFrame, isAddrInUseError, isBatchRequest, isSubscribe, isUnsubscribe };
|
|
3957
4036
|
//# sourceMappingURL=index.mjs.map
|
|
3958
4037
|
//# sourceMappingURL=index.mjs.map
|