@qontinui/ui-bridge-native 0.1.4 → 0.1.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.
- package/dist/control/{index.d.mts → action-executor.d.ts} +6 -10
- package/dist/control/action-executor.d.ts.map +1 -0
- package/dist/control/index.d.ts +5 -91
- package/dist/control/index.d.ts.map +1 -0
- package/dist/control/index.js +1 -1
- package/dist/control/index.js.map +1 -1
- package/dist/control/index.mjs +1 -1
- package/dist/control/index.mjs.map +1 -1
- package/dist/{types-BCYWwyVy.d.ts → control/types.d.ts} +17 -18
- package/dist/control/types.d.ts.map +1 -0
- package/dist/core/element-identifier.d.ts +41 -0
- package/dist/core/element-identifier.d.ts.map +1 -0
- package/dist/core/index.d.ts +6 -43
- package/dist/core/index.d.ts.map +1 -0
- package/dist/{registry-B8A_EoxS.d.ts → core/registry.d.ts} +10 -13
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/{types-BPNuYxDx.d.ts → core/types.d.ts} +30 -30
- package/dist/core/types.d.ts.map +1 -0
- package/dist/debug/index.d.ts +4 -44
- package/dist/debug/index.d.ts.map +1 -0
- package/dist/debug/index.js.map +1 -1
- package/dist/debug/index.mjs.map +1 -1
- package/dist/debug/{index.d.mts → inspector.d.ts} +3 -6
- package/dist/debug/inspector.d.ts.map +1 -0
- package/dist/design/{index.d.mts → design-inspector-native.d.ts} +7 -11
- package/dist/design/design-inspector-native.d.ts.map +1 -0
- package/dist/{design-types-BHr6Q1FX.d.ts → design/design-types.d.ts} +10 -11
- package/dist/design/design-types.d.ts.map +1 -0
- package/dist/design/index.d.ts +5 -60
- package/dist/design/index.d.ts.map +1 -0
- package/dist/index.d.ts +28 -73
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +129 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +129 -23
- package/dist/index.mjs.map +1 -1
- package/dist/react/UIBridgeNativeProvider.d.ts +147 -0
- package/dist/react/UIBridgeNativeProvider.d.ts.map +1 -0
- package/dist/react/index.d.ts +8 -69
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +138 -23
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +138 -23
- package/dist/react/index.mjs.map +1 -1
- package/dist/react/{index.d.mts → useAutoRegister.d.ts} +7 -15
- package/dist/react/useAutoRegister.d.ts.map +1 -0
- package/dist/react/useUIBridge.d.ts +103 -0
- package/dist/react/useUIBridge.d.ts.map +1 -0
- package/dist/react/useUIComponent.d.ts +112 -0
- package/dist/react/useUIComponent.d.ts.map +1 -0
- package/dist/react/useUIElement.d.ts +162 -0
- package/dist/react/useUIElement.d.ts.map +1 -0
- package/dist/server/design-handlers.d.ts +47 -0
- package/dist/server/design-handlers.d.ts.map +1 -0
- package/dist/server/handlers.d.ts +20 -0
- package/dist/server/handlers.d.ts.map +1 -0
- package/dist/server/http-server.d.ts +247 -0
- package/dist/server/http-server.d.ts.map +1 -0
- package/dist/server/index.d.ts +13 -117
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +102 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +102 -1
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/types.d.ts +200 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/ws-connection.d.ts +48 -0
- package/dist/server/ws-connection.d.ts.map +1 -0
- package/dist/server/ws-event-bridge.d.ts +113 -0
- package/dist/server/ws-event-bridge.d.ts.map +1 -0
- package/dist/server/ws-protocol.d.ts +48 -0
- package/dist/server/ws-protocol.d.ts.map +1 -0
- package/dist/server/ws-types.d.ts +65 -0
- package/dist/server/ws-types.d.ts.map +1 -0
- package/dist/transport/CloudRelayClient.d.ts +51 -0
- package/dist/transport/CloudRelayClient.d.ts.map +1 -0
- package/dist/transport/DeviceAnnouncer.d.ts +75 -0
- package/dist/transport/DeviceAnnouncer.d.ts.map +1 -0
- package/dist/transport/index.d.ts +3 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/core/index.d.mts +0 -46
- package/dist/design-types-BHr6Q1FX.d.mts +0 -205
- package/dist/http-server-B7KudcYJ.d.ts +0 -622
- package/dist/http-server-D7uVANBU.d.mts +0 -622
- package/dist/index.d.mts +0 -76
- package/dist/registry-DhbGbl9c.d.mts +0 -215
- package/dist/server/index.d.mts +0 -119
- package/dist/types-BPNuYxDx.d.mts +0 -383
- package/dist/types-Bcj7ji97.d.mts +0 -177
- package/dist/useUIBridge-CDZbWxII.d.ts +0 -571
- package/dist/useUIBridge-DfIEq9EQ.d.mts +0 -571
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createContext, useRef, useState, useCallback, useEffect, useMemo, useContext } from 'react';
|
|
2
|
+
import { Dimensions, StyleSheet, Platform, TouchableOpacity, Text, Modal, View, ScrollView } from 'react-native';
|
|
2
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
-
import { Dimensions, StyleSheet, TouchableOpacity, Text, Modal, View, ScrollView } from 'react-native';
|
|
4
4
|
|
|
5
5
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
6
6
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
@@ -739,7 +739,7 @@ var DefaultNativeActionExecutor = class {
|
|
|
739
739
|
if (!params?.text) {
|
|
740
740
|
throw new Error("Type action requires text parameter");
|
|
741
741
|
}
|
|
742
|
-
if (params.clearFirst) {
|
|
742
|
+
if (params.clearFirst || params.clear) {
|
|
743
743
|
await this.performClear(element, props);
|
|
744
744
|
}
|
|
745
745
|
if (params.delay && params.delay > 0) {
|
|
@@ -1972,6 +1972,10 @@ var WS_ROUTES = [
|
|
|
1972
1972
|
{ pattern: "health", handler: "health", httpMethods: ["GET"] },
|
|
1973
1973
|
// Elements
|
|
1974
1974
|
{ pattern: "control/elements", handler: "getElements", httpMethods: ["GET"] },
|
|
1975
|
+
// Flat alias — matches the runner UI Bridge's `/ui-bridge/elements` path so
|
|
1976
|
+
// agents can use the same URL across runner + mobile without remembering
|
|
1977
|
+
// the `control/` prefix. Delegates to the same handler.
|
|
1978
|
+
{ pattern: "elements", handler: "getElements", httpMethods: ["GET"] },
|
|
1975
1979
|
{ pattern: "control/element/:id", handler: "getElement", httpMethods: ["GET"] },
|
|
1976
1980
|
{ pattern: "control/element/:id/state", handler: "getElementState", httpMethods: ["GET"] },
|
|
1977
1981
|
{ pattern: "control/element/:id/action", handler: "executeAction", httpMethods: ["POST"] },
|
|
@@ -2022,6 +2026,87 @@ var WS_ROUTES = [
|
|
|
2022
2026
|
// Meta / Introspection
|
|
2023
2027
|
{ pattern: "meta/methods", handler: "getMethods", httpMethods: ["GET"] }
|
|
2024
2028
|
];
|
|
2029
|
+
var HANDLER_DESCRIPTIONS = {
|
|
2030
|
+
health: "Liveness probe; returns app metadata + element count",
|
|
2031
|
+
getElements: "Flat list of registered UI elements",
|
|
2032
|
+
getElement: "Single element by id",
|
|
2033
|
+
getElementState: "Dynamic state (value, focused, checked) for one element",
|
|
2034
|
+
executeAction: 'Run an action on an element (see "actions" below for names)',
|
|
2035
|
+
getComponents: "Higher-level components with action schemas",
|
|
2036
|
+
getComponent: "Component detail + per-action paramSchema",
|
|
2037
|
+
executeComponentAction: "Invoke a component action directly (preferred over button clicks)",
|
|
2038
|
+
find: "AI-powered element search by natural-language query",
|
|
2039
|
+
getSnapshot: "Full snapshot: elements + route + state. Supports ?visibleOnly=true and ?currentRouteOnly=true",
|
|
2040
|
+
getWorkflows: "List registered workflows",
|
|
2041
|
+
runWorkflow: "Trigger a workflow by id",
|
|
2042
|
+
pageRefresh: "Reload the current route",
|
|
2043
|
+
pageNavigate: "Imperative router.push(url) \u2014 preferred over tapping tab buttons",
|
|
2044
|
+
pageReplace: "router.replace(url)",
|
|
2045
|
+
pageGoBack: "router.back()",
|
|
2046
|
+
pageGoForward: "router.forward()",
|
|
2047
|
+
getScreenshot: "PNG screenshot of the current screen",
|
|
2048
|
+
getElementStyles: "Computed styles for an element (design review)",
|
|
2049
|
+
getElementStateStyles: "Computed styles per interaction state (hover/focus/disabled)",
|
|
2050
|
+
getDesignSnapshot: "Visual + style snapshot for design review",
|
|
2051
|
+
getResponsiveSnapshots: "Screenshots at multiple viewport widths",
|
|
2052
|
+
runDesignAudit: "Accessibility + visual audit",
|
|
2053
|
+
loadStyleGuide: "Load a design system style guide",
|
|
2054
|
+
getStyleGuide: "Fetch the currently loaded style guide",
|
|
2055
|
+
clearStyleGuide: "Unload the style guide",
|
|
2056
|
+
evaluateQuality: "Score the current UI against a quality context",
|
|
2057
|
+
getQualityContexts: "List available quality evaluation contexts",
|
|
2058
|
+
saveBaseline: "Save a quality baseline snapshot",
|
|
2059
|
+
diffBaseline: "Diff current UI against a saved baseline",
|
|
2060
|
+
getMethods: "List every handler name (legacy introspection)"
|
|
2061
|
+
};
|
|
2062
|
+
var ACTION_REFERENCE = [
|
|
2063
|
+
{ name: "press", aliases: ["click"], params: "PressActionParams (optional position)" },
|
|
2064
|
+
{ name: "longPress", params: "PressActionParams (optional position)" },
|
|
2065
|
+
{ name: "doubleTap", params: "none" },
|
|
2066
|
+
{
|
|
2067
|
+
name: "type",
|
|
2068
|
+
params: "TypeActionParams { text, delay?, clear? | clearFirst? } \u2014 `clear:true` replaces content atomically"
|
|
2069
|
+
},
|
|
2070
|
+
{ name: "clear", params: "none \u2014 empties the input" },
|
|
2071
|
+
{ name: "focus", params: "none" },
|
|
2072
|
+
{ name: "blur", params: "none" },
|
|
2073
|
+
{ name: "scroll", params: "ScrollActionParams { offset? {x,y}, to? }" },
|
|
2074
|
+
{ name: "swipe", params: "SwipeActionParams { direction, distance }" },
|
|
2075
|
+
{ name: "toggle", params: "none \u2014 flips boolean controls" }
|
|
2076
|
+
];
|
|
2077
|
+
function buildRoutesPayload() {
|
|
2078
|
+
const entries = [];
|
|
2079
|
+
for (const r of WS_ROUTES) {
|
|
2080
|
+
if (!r.httpMethods) continue;
|
|
2081
|
+
for (const m of r.httpMethods) {
|
|
2082
|
+
entries.push({ method: m, path: `/ui-bridge/${r.pattern}` });
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
entries.push({ method: "GET", path: "/ui-bridge/_help" });
|
|
2086
|
+
entries.push({ method: "GET", path: "/ui-bridge/_routes" });
|
|
2087
|
+
entries.sort((a, b) => a.path.localeCompare(b.path) || a.method.localeCompare(b.method));
|
|
2088
|
+
return { routes: entries, count: entries.length };
|
|
2089
|
+
}
|
|
2090
|
+
function buildHelpPayload() {
|
|
2091
|
+
return {
|
|
2092
|
+
version: 1,
|
|
2093
|
+
description: "UI Bridge Native HTTP surface. Prefix every path with /ui-bridge/.",
|
|
2094
|
+
routes: WS_ROUTES.map((r) => ({
|
|
2095
|
+
pattern: r.pattern,
|
|
2096
|
+
httpMethods: r.httpMethods ?? [],
|
|
2097
|
+
wsOnly: !r.httpMethods,
|
|
2098
|
+
handler: r.handler,
|
|
2099
|
+
description: HANDLER_DESCRIPTIONS[r.handler] ?? ""
|
|
2100
|
+
})),
|
|
2101
|
+
actions: ACTION_REFERENCE,
|
|
2102
|
+
tips: [
|
|
2103
|
+
"Start with `GET /ui-bridge/control/snapshot?visibleOnly=true` to see what the user actually sees.",
|
|
2104
|
+
"Prefer `control/component/:id/action/:actionId` over button presses \u2014 typed paramSchema, no button-id guessing.",
|
|
2105
|
+
"Use `pageNavigate` for tab switches instead of pressing tab buttons; gesture state often swallows clicks.",
|
|
2106
|
+
"The `type` action supports `clear:true` to replace existing text atomically in one call."
|
|
2107
|
+
]
|
|
2108
|
+
};
|
|
2109
|
+
}
|
|
2025
2110
|
var NativeUIBridgeServer = class {
|
|
2026
2111
|
constructor(registry, executor, config = {}) {
|
|
2027
2112
|
this.registry = registry;
|
|
@@ -2038,7 +2123,9 @@ var NativeUIBridgeServer = class {
|
|
|
2038
2123
|
cors: true,
|
|
2039
2124
|
...config
|
|
2040
2125
|
};
|
|
2041
|
-
this.handlers = createServerHandlers(registry, executor
|
|
2126
|
+
this.handlers = createServerHandlers(registry, executor, {
|
|
2127
|
+
appInfo: this.config.appInfo
|
|
2128
|
+
});
|
|
2042
2129
|
this.handlers.getMethods = async () => {
|
|
2043
2130
|
const methods = WS_ROUTES.map((r) => ({
|
|
2044
2131
|
method: r.pattern,
|
|
@@ -2842,6 +2929,20 @@ var NativeUIBridgeServer = class {
|
|
|
2842
2929
|
};
|
|
2843
2930
|
}
|
|
2844
2931
|
const stripped = path.slice(PREFIX.length);
|
|
2932
|
+
if (method === "GET" && stripped === "_help") {
|
|
2933
|
+
return {
|
|
2934
|
+
success: true,
|
|
2935
|
+
data: buildHelpPayload(),
|
|
2936
|
+
timestamp: Date.now()
|
|
2937
|
+
};
|
|
2938
|
+
}
|
|
2939
|
+
if (method === "GET" && stripped === "_routes") {
|
|
2940
|
+
return {
|
|
2941
|
+
success: true,
|
|
2942
|
+
data: buildRoutesPayload(),
|
|
2943
|
+
timestamp: Date.now()
|
|
2944
|
+
};
|
|
2945
|
+
}
|
|
2845
2946
|
let patternMatchedButWrongVerb = false;
|
|
2846
2947
|
for (const route of WS_ROUTES) {
|
|
2847
2948
|
const pathParams = parsePath(route.pattern, stripped);
|
|
@@ -3142,8 +3243,6 @@ var WebSocketEventBridge = class {
|
|
|
3142
3243
|
}, this.heartbeatIntervalMs);
|
|
3143
3244
|
}
|
|
3144
3245
|
};
|
|
3145
|
-
|
|
3146
|
-
// src/transport/DeviceAnnouncer.ts
|
|
3147
3246
|
var DEFAULT_PORT = 8087;
|
|
3148
3247
|
var RECONNECT_INITIAL_DELAY_MS = 2e3;
|
|
3149
3248
|
var RECONNECT_MAX_DELAY_MS = 6e4;
|
|
@@ -3164,15 +3263,27 @@ var DeviceAnnouncer = class {
|
|
|
3164
3263
|
}
|
|
3165
3264
|
// ── mDNS ──────────────────────────────────────────────────────────────────
|
|
3166
3265
|
/**
|
|
3167
|
-
* Start mDNS advertisement
|
|
3266
|
+
* Start mDNS advertisement.
|
|
3168
3267
|
*
|
|
3169
|
-
*
|
|
3268
|
+
* The consumer must pass the `Zeroconf` constructor (from `react-native-zeroconf`)
|
|
3269
|
+
* explicitly; otherwise this is a no-op.
|
|
3270
|
+
*
|
|
3271
|
+
* Rationale: Metro's `require()` throws an uncatchable module-load error if the
|
|
3272
|
+
* bundle doesn't include the named package. That error escapes async try/catch
|
|
3273
|
+
* boundaries and crashes the app. We avoid it by never calling `require()`
|
|
3274
|
+
* ourselves — the consumer imports the package when they know it's installed.
|
|
3275
|
+
*
|
|
3276
|
+
* @param ZeroconfCtor - constructor from `import Zeroconf from 'react-native-zeroconf'`
|
|
3170
3277
|
*/
|
|
3171
|
-
async startMdnsAdvertise() {
|
|
3278
|
+
async startMdnsAdvertise(ZeroconfCtor) {
|
|
3279
|
+
if (!ZeroconfCtor) {
|
|
3280
|
+
console.log(
|
|
3281
|
+
"[DeviceAnnouncer] mDNS advertisement skipped (no Zeroconf constructor provided). Pass one to enable mDNS."
|
|
3282
|
+
);
|
|
3283
|
+
return;
|
|
3284
|
+
}
|
|
3172
3285
|
try {
|
|
3173
|
-
|
|
3174
|
-
const Zeroconf = ZeroconfModule.default ?? ZeroconfModule;
|
|
3175
|
-
this.zeroconf = new Zeroconf();
|
|
3286
|
+
this.zeroconf = new ZeroconfCtor();
|
|
3176
3287
|
const port = this.config.port ?? DEFAULT_PORT;
|
|
3177
3288
|
const serviceName = `UIBridge-${this.config.deviceId.slice(0, 8)}`;
|
|
3178
3289
|
this.zeroconf.publishService("_uibridge", "_tcp.", "local.", serviceName, port, {
|
|
@@ -3183,10 +3294,8 @@ var DeviceAnnouncer = class {
|
|
|
3183
3294
|
});
|
|
3184
3295
|
this.state = { ...this.state, mdnsActive: true };
|
|
3185
3296
|
console.log(`[DeviceAnnouncer] mDNS: advertising "${serviceName}" on port ${port}`);
|
|
3186
|
-
} catch (
|
|
3187
|
-
console.warn(
|
|
3188
|
-
"[DeviceAnnouncer] react-native-zeroconf not available \u2014 mDNS advertisement skipped. Install it with: npx expo install react-native-zeroconf"
|
|
3189
|
-
);
|
|
3297
|
+
} catch (err) {
|
|
3298
|
+
console.warn("[DeviceAnnouncer] mDNS start failed:", err);
|
|
3190
3299
|
}
|
|
3191
3300
|
}
|
|
3192
3301
|
// ── Cloud relay ───────────────────────────────────────────────────────────
|
|
@@ -3291,12 +3400,7 @@ function generateHex(bytes) {
|
|
|
3291
3400
|
return Array.from(arr).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
3292
3401
|
}
|
|
3293
3402
|
function getPlatform() {
|
|
3294
|
-
|
|
3295
|
-
const { Platform } = __require("react-native");
|
|
3296
|
-
return Platform.OS ?? "unknown";
|
|
3297
|
-
} catch {
|
|
3298
|
-
return "unknown";
|
|
3299
|
-
}
|
|
3403
|
+
return Platform?.OS ?? "unknown";
|
|
3300
3404
|
}
|
|
3301
3405
|
|
|
3302
3406
|
// src/transport/CloudRelayClient.ts
|
|
@@ -3503,7 +3607,8 @@ function UIBridgeNativeProvider({
|
|
|
3503
3607
|
}
|
|
3504
3608
|
const server = createNativeServer(registry, executor, {
|
|
3505
3609
|
serverPort: config.serverPort || 8087,
|
|
3506
|
-
cors: true
|
|
3610
|
+
cors: true,
|
|
3611
|
+
appInfo: config.appInfo
|
|
3507
3612
|
});
|
|
3508
3613
|
server.setAdapter(serverAdapter);
|
|
3509
3614
|
if (navigationProvider) {
|
|
@@ -3590,7 +3695,8 @@ function UIBridgeNativeProvider({
|
|
|
3590
3695
|
try {
|
|
3591
3696
|
const bareServer = createNativeServer(registry, executor, {
|
|
3592
3697
|
serverPort: config.serverPort || 8087,
|
|
3593
|
-
cors: true
|
|
3698
|
+
cors: true,
|
|
3699
|
+
appInfo: config.appInfo
|
|
3594
3700
|
});
|
|
3595
3701
|
if (navigationProvider) bareServer.setNavigationProvider(navigationProvider);
|
|
3596
3702
|
if (screenshotProvider) bareServer.setScreenshotProvider(screenshotProvider);
|