catalyst-core 0.2.0-beta.3 → 0.3.0-beta.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.
- package/babel.native.config.cjs +8 -0
- package/bin/catalyst.js +49 -105
- package/changelog.md +8 -0
- package/dist/caching.js +1 -1
- package/dist/index.jsx +8 -0
- package/dist/logger.js +74 -3
- package/dist/native/androidSetup.js +300 -8
- package/dist/native/bridge/WebBridge.js +481 -59
- package/dist/native/bridge/constants/NativeInterfaces.js +290 -45
- package/dist/native/bridge/errors.js +250 -26
- package/dist/native/bridge/hooks/index.js +125 -1
- package/dist/native/bridge/hooks/useCamera.js +347 -9
- package/dist/native/bridge/hooks/useDataProtection.js +200 -2
- package/dist/native/bridge/hooks/useDeviceInfo.js +71 -2
- package/dist/native/bridge/hooks/useFilePicker.js +429 -2
- package/dist/native/bridge/hooks/useGoogleSignIn.js +81 -1
- package/dist/native/bridge/hooks/useHapticFeedback.js +196 -1
- package/dist/native/bridge/hooks/useIntent.js +95 -1
- package/dist/native/bridge/hooks/useNativeTransition.js +202 -27
- package/dist/native/bridge/hooks/useNetworkStatus.js +84 -3
- package/dist/native/bridge/hooks/useNotification.js +318 -2
- package/dist/native/bridge/hooks/useSafeArea.js +84 -2
- package/dist/native/bridge/hooks/useVideoStream.js +434 -6
- package/dist/native/bridge/hooks/utils.js +27 -1
- package/dist/native/bridge/hooks.js +16 -1
- package/dist/native/bridge/perf/collectors/ApiCollector.js +66 -3
- package/dist/native/bridge/perf/collectors/CacheCollector.js +186 -11
- package/dist/native/bridge/perf/collectors/HookCollector.js +141 -19
- package/dist/native/bridge/perf/collectors/InsightsCollector.js +481 -23
- package/dist/native/bridge/perf/collectors/InteractionCollector.js +245 -10
- package/dist/native/bridge/perf/collectors/KeyboardCollector.js +107 -8
- package/dist/native/bridge/perf/collectors/NavigationCollector.js +273 -32
- package/dist/native/bridge/perf/collectors/NetworkTimingCollector.js +178 -2
- package/dist/native/bridge/perf/collectors/RenderCollector.js +258 -14
- package/dist/native/bridge/perf/collectors/ScrollCollector.js +95 -9
- package/dist/native/bridge/perf/collectors/ThreadCollector.js +90 -6
- package/dist/native/bridge/perf/core/constants.js +103 -20
- package/dist/native/bridge/perf/core/measure.js +179 -30
- package/dist/native/bridge/perf/core/session.js +89 -23
- package/dist/native/bridge/perf/core/store.js +554 -1
- package/dist/native/bridge/perf/core/summary.js +174 -1
- package/dist/native/bridge/perf/core/traceExport.js +240 -1
- package/dist/native/bridge/perf/core/waterfalls.js +146 -1
- package/dist/native/bridge/perf/index.js +359 -38
- package/dist/native/bridge/safeArea.js +53 -5
- package/dist/native/bridge/standardizedHooks.js +595 -82
- package/dist/native/bridge/useBaseHook.js +274 -38
- package/dist/native/bridge/utils/CameraUtils.js +201 -56
- package/dist/native/bridge/utils/FileObjectConverter.js +129 -18
- package/dist/native/bridge/utils/NativeBridge.js +425 -141
- package/dist/native/buildAndroid/assets.js +510 -13
- package/dist/native/buildAndroid/build.js +296 -19
- package/dist/native/buildAndroid/config.js +87 -1
- package/dist/native/buildAndroid/index.js +374 -1
- package/dist/native/buildAppAndroid.js +34 -2
- package/dist/native/buildAppIos.js +62 -2
- package/dist/native/buildIos/assets.js +609 -8
- package/dist/native/buildIos/build.js +639 -20
- package/dist/native/buildIos/config.js +294 -12
- package/dist/native/buildIos/index.js +343 -6
- package/dist/native/buildIos/plugins.js +343 -16
- package/dist/native/internal-plugins/device-info-plugin/android/DeviceInfoPlugin.kt +43 -0
- package/dist/native/internal-plugins/device-info-plugin/ios/DeviceInfoPlugin.swift +28 -0
- package/dist/native/internal-plugins/device-info-plugin/manifest.json +19 -0
- package/dist/native/internalPluginUtils.js +232 -7
- package/dist/native/package.json +3 -0
- package/dist/native/plugin-bridge/PluginBridge.js +227 -1
- package/dist/native/pluginComposerAndroid.js +407 -23
- package/dist/native/pluginComposerIos.js +435 -11
- package/dist/native/renameAndroidProject.js +1094 -88
- package/dist/native/setupEmulatorIos.js +289 -22
- package/dist/native/setupServer.js +160 -19
- package/dist/native/terminalProgress.js +199 -11
- package/dist/native/utils.js +193 -15
- package/dist/offline/catalyst-sw.js +145 -1
- package/dist/offline/registerServiceWorker.js +33 -1
- package/dist/otel.js +375 -46
- package/dist/router/ClientRouter.js +14 -2
- package/dist/router/ServerRouter.js +9 -1
- package/dist/router.js +1 -1
- package/dist/scripts/build.js +112 -3
- package/dist/scripts/checkVersion.js +3 -1
- package/dist/scripts/cleanCache.js +30 -1
- package/dist/scripts/generateOfflineManifest.js +116 -1
- package/dist/scripts/loadEnvironmentVariables.js +32 -6
- package/dist/scripts/plugins.js +309 -1
- package/dist/scripts/preServerInit.js +13 -0
- package/dist/scripts/scriptUtils.js +54 -3
- package/dist/scripts/serve.js +51 -4
- package/dist/scripts/start.js +47 -10
- package/dist/scripts/validator.js +149 -1
- package/dist/sentry.cjs +127 -0
- package/dist/sentry.js +125 -5
- package/dist/server/expressServer.js +250 -5
- package/dist/server/manifestCache.js +36 -0
- package/dist/server/renderer/ChunkExtractor.js +144 -0
- package/dist/server/renderer/document/Body.jsx +59 -0
- package/dist/server/renderer/document/FastRefresh.jsx +20 -0
- package/dist/server/renderer/document/Head.jsx +60 -0
- package/dist/server/renderer/document/index.jsx +2 -0
- package/dist/server/renderer/extract.js +149 -31
- package/dist/server/renderer/handler.jsx +433 -0
- package/dist/server/renderer/index.js +8 -1
- package/dist/server/renderer/render.js +47 -0
- package/dist/server/utils/botDetectionMiddleware.js +29 -0
- package/dist/server/utils/cjsRequire.js +10 -0
- package/dist/server/utils/userAgentUtil.js +87 -9
- package/dist/server/utils/validator.js +164 -1
- package/dist/vite/FastRefresh.jsx +20 -0
- package/dist/vite/inject-cache-key-plugin.js +276 -0
- package/dist/vite/loadCustomViteConfig.js +22 -0
- package/dist/vite/manifest-categorization-plugin.js +455 -0
- package/dist/vite/node-loader.mjs +458 -0
- package/dist/vite/scssParams.js +21 -0
- package/dist/vite/vite.config.client.js +130 -0
- package/dist/vite/vite.config.js +422 -0
- package/dist/vite/vite.config.server.js +84 -0
- package/dist/web-router/components/MetaTag.jsx +34 -0
- package/dist/web-router/components/RouterDataProvider.jsx +332 -0
- package/dist/web-router/components/Split.jsx +200 -0
- package/dist/web-router/components/SplitInview.jsx +106 -0
- package/dist/web-router/components/SsrRequestContext.jsx +14 -0
- package/dist/web-router/context.jsx +12 -0
- package/dist/web-router/hooks.jsx +72 -0
- package/dist/web-router/types/components/MetaTag.d.ts +2 -0
- package/dist/web-router/types/components/RouterDataProvider.d.ts +95 -0
- package/dist/web-router/types/context.d.ts +14 -0
- package/dist/web-router/types/hooks.d.ts +1 -0
- package/dist/web-router/types/index.d.ts +3 -0
- package/dist/web-router/types/utils/metaDataUtils.d.ts +24 -0
- package/dist/web-router/utils/metaDataUtils.jsx +119 -0
- package/mcp_v2/conversion-tasks.json +35 -17
- package/mcp_v2/knowledge-base.json +124 -13
- package/mcp_v2/lib/helpers.js +10 -0
- package/mcp_v2/mcp.js +4 -4
- package/mcp_v2/package.json +1 -0
- package/mcp_v2/tools/build.js +116 -20
- package/mcp_v2/tools/conversion.js +106 -5
- package/mcp_v2/tools/tasks.js +18 -14
- package/package.json +35 -68
- package/babel.config.js +0 -32
- package/dist/index.js +0 -1
- package/dist/scripts/devBuild.js +0 -3
- package/dist/scripts/devServe.js +0 -3
- package/dist/scripts/loadScriptsBeforeServerStarts.js +0 -4
- package/dist/scripts/registerAliases.js +0 -6
- package/dist/server/renderer/document/Body.js +0 -11
- package/dist/server/renderer/document/Head.js +0 -9
- package/dist/server/renderer/document/index.js +0 -1
- package/dist/server/renderer/handler.js +0 -47
- package/dist/server/startServer.js +0 -57
- package/dist/webpack/babel-plugins/remove-client.plugin.js +0 -5
- package/dist/webpack/babel-plugins/remove-ssr.plugin.js +0 -5
- package/dist/webpack/babel.config.client.js +0 -1
- package/dist/webpack/babel.config.ssr.js +0 -1
- package/dist/webpack/base.babel.js +0 -7
- package/dist/webpack/development.client.babel.js +0 -10
- package/dist/webpack/production.client.babel.js +0 -4
- package/dist/webpack/production.ssr.babel.js +0 -8
- package/dist/webpack/scssParams.js +0 -9
|
@@ -1,6 +1,434 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useVideoStream = void 0;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
var _NativeBridge = _interopRequireDefault(require("../utils/NativeBridge.js"));
|
|
9
|
+
var _NativeInterfaces = require("../constants/NativeInterfaces.js");
|
|
10
|
+
var _useBaseHook = require("../useBaseHook.js");
|
|
11
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */
|
|
13
|
+
|
|
14
|
+
const STREAM_STATE_DEFAULT = {
|
|
15
|
+
zoom: null,
|
|
16
|
+
minZoom: null,
|
|
17
|
+
maxZoom: null,
|
|
18
|
+
torchOn: false,
|
|
19
|
+
fpsMin: null,
|
|
20
|
+
fpsMax: null
|
|
21
|
+
};
|
|
22
|
+
const useVideoStream = ({
|
|
23
|
+
onQRDetected,
|
|
24
|
+
webFallback
|
|
25
|
+
} = {}) => {
|
|
26
|
+
const base = (0, _useBaseHook.useBaseHook)("useVideoStream", {
|
|
27
|
+
hasWebFallback: true,
|
|
28
|
+
webFallback
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Native stream state
|
|
32
|
+
const [isStreaming, setIsStreaming] = (0, _react.useState)(false);
|
|
33
|
+
const [streamState, setStreamState] = (0, _react.useState)(STREAM_STATE_DEFAULT);
|
|
34
|
+
const onQRDetectedRef = (0, _react.useRef)(onQRDetected);
|
|
35
|
+
onQRDetectedRef.current = onQRDetected;
|
|
36
|
+
const viewfinderRef = (0, _react.useRef)(null);
|
|
37
|
+
|
|
38
|
+
// Web fallback stream state — always declared (Rules of Hooks)
|
|
39
|
+
const [isStreamingWeb, setIsStreamingWeb] = (0, _react.useState)(false);
|
|
40
|
+
const [streamStateWeb, setStreamStateWeb] = (0, _react.useState)(STREAM_STATE_DEFAULT);
|
|
41
|
+
const mediaStreamRef = (0, _react.useRef)(null);
|
|
42
|
+
const facingModeRef = (0, _react.useRef)("environment");
|
|
43
|
+
|
|
44
|
+
// Web fallback: stop active stream when webFallbackActive toggles off
|
|
45
|
+
(0, _react.useEffect)(() => {
|
|
46
|
+
if (!base.webFallbackActive && mediaStreamRef.current) {
|
|
47
|
+
mediaStreamRef.current.getTracks().forEach(t => t.stop());
|
|
48
|
+
mediaStreamRef.current = null;
|
|
49
|
+
setIsStreamingWeb(false);
|
|
50
|
+
setStreamStateWeb(STREAM_STATE_DEFAULT);
|
|
51
|
+
}
|
|
52
|
+
}, [base.webFallbackActive]);
|
|
53
|
+
|
|
54
|
+
// Web fallback: cleanup on unmount
|
|
55
|
+
(0, _react.useEffect)(() => {
|
|
56
|
+
return () => {
|
|
57
|
+
if (mediaStreamRef.current) {
|
|
58
|
+
mediaStreamRef.current.getTracks().forEach(t => t.stop());
|
|
59
|
+
mediaStreamRef.current = null;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}, []);
|
|
63
|
+
const applyTrackConstraints = (0, _react.useCallback)(async constraints => {
|
|
64
|
+
const track = mediaStreamRef.current?.getVideoTracks()[0];
|
|
65
|
+
if (!track) return;
|
|
66
|
+
try {
|
|
67
|
+
await track.applyConstraints(constraints);
|
|
68
|
+
} catch (e) {
|
|
69
|
+
base.setError({
|
|
70
|
+
message: `applyConstraints failed: ${e.message}`
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}, [base]);
|
|
74
|
+
const webStart = (0, _react.useCallback)(async (options = {}) => {
|
|
75
|
+
if (!window.isSecureContext) {
|
|
76
|
+
base.setError({
|
|
77
|
+
message: "getUserMedia requires a secure context (HTTPS or localhost)"
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (!navigator.mediaDevices?.getUserMedia) {
|
|
82
|
+
base.setError({
|
|
83
|
+
message: "getUserMedia is not available in this browser"
|
|
84
|
+
});
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
if (mediaStreamRef.current) return;
|
|
89
|
+
base.setLoading(true);
|
|
90
|
+
const constraints = {
|
|
91
|
+
video: {
|
|
92
|
+
facingMode: {
|
|
93
|
+
ideal: facingModeRef.current
|
|
94
|
+
},
|
|
95
|
+
...(options.fps ? {
|
|
96
|
+
frameRate: {
|
|
97
|
+
ideal: options.fps
|
|
98
|
+
}
|
|
99
|
+
} : {})
|
|
100
|
+
},
|
|
101
|
+
audio: false
|
|
102
|
+
};
|
|
103
|
+
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
104
|
+
mediaStreamRef.current = stream;
|
|
105
|
+
setIsStreamingWeb(true);
|
|
106
|
+
base.setLoading(false);
|
|
107
|
+
const track = stream.getVideoTracks()[0];
|
|
108
|
+
const caps = track?.getCapabilities?.() || {};
|
|
109
|
+
setStreamStateWeb(prev => ({
|
|
110
|
+
...prev,
|
|
111
|
+
minZoom: caps.zoom?.min ?? null,
|
|
112
|
+
maxZoom: caps.zoom?.max ?? null,
|
|
113
|
+
zoom: caps.zoom?.min ?? null
|
|
114
|
+
}));
|
|
115
|
+
} catch (e) {
|
|
116
|
+
base.setLoading(false);
|
|
117
|
+
base.setError({
|
|
118
|
+
message: e.message || "getUserMedia failed"
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}, [base]);
|
|
122
|
+
const webStop = (0, _react.useCallback)(() => {
|
|
123
|
+
if (!mediaStreamRef.current) return;
|
|
124
|
+
mediaStreamRef.current.getTracks().forEach(t => t.stop());
|
|
125
|
+
mediaStreamRef.current = null;
|
|
126
|
+
setIsStreamingWeb(false);
|
|
127
|
+
setStreamStateWeb(STREAM_STATE_DEFAULT);
|
|
128
|
+
}, []);
|
|
129
|
+
const webFlip = (0, _react.useCallback)(async () => {
|
|
130
|
+
facingModeRef.current = facingModeRef.current === "environment" ? "user" : "environment";
|
|
131
|
+
if (mediaStreamRef.current) {
|
|
132
|
+
webStop();
|
|
133
|
+
await webStart();
|
|
134
|
+
}
|
|
135
|
+
}, [webStart, webStop]);
|
|
136
|
+
const webSendCommand = (0, _react.useCallback)(async (type, value) => {
|
|
137
|
+
if (!isStreamingWeb) {
|
|
138
|
+
base.setError({
|
|
139
|
+
message: `sendCommand('${type}') called but stream is not active`
|
|
140
|
+
});
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
switch (type) {
|
|
144
|
+
case "zoom":
|
|
145
|
+
{
|
|
146
|
+
if (typeof value !== "number" || value < 1.0) {
|
|
147
|
+
base.setError({
|
|
148
|
+
message: `sendCommand zoom: value must be a multiplier >= 1.0, got ${value}`
|
|
149
|
+
});
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
await applyTrackConstraints({
|
|
153
|
+
advanced: [{
|
|
154
|
+
zoom: value
|
|
155
|
+
}]
|
|
156
|
+
});
|
|
157
|
+
setStreamStateWeb(prev => ({
|
|
158
|
+
...prev,
|
|
159
|
+
zoom: value
|
|
160
|
+
}));
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
case "torch":
|
|
164
|
+
{
|
|
165
|
+
if (typeof value !== "boolean") {
|
|
166
|
+
base.setError({
|
|
167
|
+
message: `sendCommand torch: value must be boolean, got ${value}`
|
|
168
|
+
});
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
await applyTrackConstraints({
|
|
172
|
+
advanced: [{
|
|
173
|
+
torch: value
|
|
174
|
+
}]
|
|
175
|
+
});
|
|
176
|
+
setStreamStateWeb(prev => ({
|
|
177
|
+
...prev,
|
|
178
|
+
torchOn: value
|
|
179
|
+
}));
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
case "fps":
|
|
183
|
+
{
|
|
184
|
+
if (typeof value !== "object" || value === null) {
|
|
185
|
+
base.setError({
|
|
186
|
+
message: `sendCommand fps: value must be { min, max }, got ${value}`
|
|
187
|
+
});
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const {
|
|
191
|
+
min = null,
|
|
192
|
+
max = null
|
|
193
|
+
} = value;
|
|
194
|
+
const frameRate = {};
|
|
195
|
+
if (min !== null) frameRate.min = min;
|
|
196
|
+
if (max !== null) frameRate.max = max;
|
|
197
|
+
await applyTrackConstraints({
|
|
198
|
+
frameRate
|
|
199
|
+
});
|
|
200
|
+
setStreamStateWeb(prev => ({
|
|
201
|
+
...prev,
|
|
202
|
+
fpsMin: min,
|
|
203
|
+
fpsMax: max
|
|
204
|
+
}));
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
default:
|
|
208
|
+
base.setError({
|
|
209
|
+
message: `sendCommand: unknown type '${type}'`
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}, [isStreamingWeb, applyTrackConstraints, base]);
|
|
213
|
+
|
|
214
|
+
// Native event registration — skipped on web (WebBridge absent or native bridge unavailable)
|
|
215
|
+
(0, _react.useEffect)(() => {
|
|
216
|
+
if (typeof window === "undefined" || !window.WebBridge || !_NativeBridge.default.isAvailable()) return;
|
|
217
|
+
window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_VIDEO_STREAM_READY, () => {
|
|
218
|
+
console.log("📹 Video stream ready");
|
|
219
|
+
setIsStreaming(true);
|
|
220
|
+
});
|
|
221
|
+
window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_VIDEO_STREAM_STOPPED, () => {
|
|
222
|
+
console.log("📹 Video stream stopped");
|
|
223
|
+
setIsStreaming(false);
|
|
224
|
+
});
|
|
225
|
+
window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_QR_DETECTED, data => {
|
|
226
|
+
try {
|
|
227
|
+
const result = typeof data === "string" ? JSON.parse(data) : data;
|
|
228
|
+
console.log("📹 QR detected:", result);
|
|
229
|
+
onQRDetectedRef.current?.(result);
|
|
230
|
+
} catch (e) {
|
|
231
|
+
base.handleNativeError("Failed to parse QR data");
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_TORCH_CHANGED, data => {
|
|
235
|
+
try {
|
|
236
|
+
const result = typeof data === "string" ? JSON.parse(data) : data;
|
|
237
|
+
const enabled = result?.enabled ?? false;
|
|
238
|
+
console.log("📹 Torch changed:", enabled);
|
|
239
|
+
setStreamState(prev => ({
|
|
240
|
+
...prev,
|
|
241
|
+
torchOn: enabled
|
|
242
|
+
}));
|
|
243
|
+
} catch (e) {
|
|
244
|
+
console.warn("[useVideoStream] Failed to parse ON_TORCH_CHANGED data:", e);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
window.WebBridge.register(_NativeInterfaces.NATIVE_CALLBACKS.ON_ZOOM_CHANGED, data => {
|
|
248
|
+
try {
|
|
249
|
+
const result = typeof data === "string" ? JSON.parse(data) : data;
|
|
250
|
+
const zoom = result?.zoomLevel ?? null;
|
|
251
|
+
const minZoom = result?.minZoom ?? null;
|
|
252
|
+
const maxZoom = result?.maxZoom ?? null;
|
|
253
|
+
console.log("📹 Zoom changed:", zoom, `(min=${minZoom} max=${maxZoom})`);
|
|
254
|
+
setStreamState(prev => ({
|
|
255
|
+
...prev,
|
|
256
|
+
zoom,
|
|
257
|
+
minZoom,
|
|
258
|
+
maxZoom
|
|
259
|
+
}));
|
|
260
|
+
} catch (e) {
|
|
261
|
+
console.warn("[useVideoStream] Failed to parse ON_ZOOM_CHANGED data:", e);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
const handleBeforeUnload = () => {
|
|
265
|
+
_NativeBridge.default.videoStream.stop();
|
|
266
|
+
};
|
|
267
|
+
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
268
|
+
return () => {
|
|
269
|
+
window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_VIDEO_STREAM_READY);
|
|
270
|
+
window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_VIDEO_STREAM_STOPPED);
|
|
271
|
+
window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_QR_DETECTED);
|
|
272
|
+
window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_TORCH_CHANGED);
|
|
273
|
+
window.WebBridge.unregister(_NativeInterfaces.NATIVE_CALLBACKS.ON_ZOOM_CHANGED);
|
|
274
|
+
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
275
|
+
_NativeBridge.default.videoStream.stop();
|
|
276
|
+
};
|
|
277
|
+
}, [base.handleNativeError]);
|
|
278
|
+
const nativeStart = (0, _react.useCallback)((options = {}) => {
|
|
279
|
+
base.executeOperation(() => {
|
|
280
|
+
console.log("[useVideoStream] start() options:", JSON.stringify(options));
|
|
281
|
+
_NativeBridge.default.videoStream.start(options);
|
|
282
|
+
}, "start video stream");
|
|
283
|
+
}, [base.executeOperation]);
|
|
284
|
+
const nativeStop = (0, _react.useCallback)(() => {
|
|
285
|
+
console.log("[useVideoStream] stop()");
|
|
286
|
+
_NativeBridge.default.videoStream.stop();
|
|
287
|
+
setIsStreaming(false);
|
|
288
|
+
}, []);
|
|
289
|
+
const nativeFlip = (0, _react.useCallback)(() => {
|
|
290
|
+
console.log("[useVideoStream] flip()");
|
|
291
|
+
_NativeBridge.default.videoStream.flip();
|
|
292
|
+
}, []);
|
|
293
|
+
const nativeSendCommand = (0, _react.useCallback)((type, value) => {
|
|
294
|
+
if (!isStreaming) {
|
|
295
|
+
base.setError({
|
|
296
|
+
message: `sendCommand('${type}') called but stream is not active`
|
|
297
|
+
});
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
console.log(`[useVideoStream] sendCommand(${type}, ${value})`);
|
|
301
|
+
switch (type) {
|
|
302
|
+
case "zoom":
|
|
303
|
+
{
|
|
304
|
+
if (typeof value !== "number" || value < 1.0) {
|
|
305
|
+
base.setError({
|
|
306
|
+
message: `sendCommand zoom: value must be a multiplier >= 1.0 (e.g. 1.0=1x, 2.0=2x), got ${value}`
|
|
307
|
+
});
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
_NativeBridge.default.videoStream.setZoom(value);
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
case "torch":
|
|
314
|
+
{
|
|
315
|
+
if (typeof value !== "boolean") {
|
|
316
|
+
base.setError({
|
|
317
|
+
message: `sendCommand torch: value must be boolean, got ${value}`
|
|
318
|
+
});
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
_NativeBridge.default.videoStream.setTorch(value);
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
case "fps":
|
|
325
|
+
{
|
|
326
|
+
if (typeof value !== "object" || value === null) {
|
|
327
|
+
base.setError({
|
|
328
|
+
message: `sendCommand fps: value must be { min, max }, got ${value}`
|
|
329
|
+
});
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const {
|
|
333
|
+
min = null,
|
|
334
|
+
max = null
|
|
335
|
+
} = value;
|
|
336
|
+
if (min !== null && (typeof min !== "number" || min < 1)) {
|
|
337
|
+
base.setError({
|
|
338
|
+
message: `sendCommand fps: min must be a positive number, got ${min}`
|
|
339
|
+
});
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
if (max !== null && (typeof max !== "number" || max < 1)) {
|
|
343
|
+
base.setError({
|
|
344
|
+
message: `sendCommand fps: max must be a positive number, got ${max}`
|
|
345
|
+
});
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (min !== null && max !== null && min > max) {
|
|
349
|
+
base.setError({
|
|
350
|
+
message: `sendCommand fps: min (${min}) must be <= max (${max})`
|
|
351
|
+
});
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
_NativeBridge.default.videoStream.setFps(min, max);
|
|
355
|
+
setStreamState(prev => ({
|
|
356
|
+
...prev,
|
|
357
|
+
fpsMin: min,
|
|
358
|
+
fpsMax: max
|
|
359
|
+
}));
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
default:
|
|
363
|
+
base.setError({
|
|
364
|
+
message: `sendCommand: unknown type '${type}'`
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
}, [isStreaming, base.setError]);
|
|
368
|
+
if (typeof window === "undefined") {
|
|
369
|
+
return {
|
|
370
|
+
isStreaming: false,
|
|
371
|
+
streamState: STREAM_STATE_DEFAULT,
|
|
372
|
+
error: null,
|
|
373
|
+
isNative: false,
|
|
374
|
+
webFallbackActive: false,
|
|
375
|
+
webFallbackDisabled: false,
|
|
376
|
+
setWebFallback: () => {},
|
|
377
|
+
start: () => {},
|
|
378
|
+
stop: () => {},
|
|
379
|
+
sendCommand: () => {},
|
|
380
|
+
flip: () => {},
|
|
381
|
+
clearError: () => {}
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
if (base.webFallbackDisabled) {
|
|
385
|
+
return {
|
|
386
|
+
isStreaming: false,
|
|
387
|
+
streamState: STREAM_STATE_DEFAULT,
|
|
388
|
+
error: null,
|
|
389
|
+
isNative: false,
|
|
390
|
+
webFallbackActive: false,
|
|
391
|
+
webFallbackDisabled: true,
|
|
392
|
+
setWebFallback: base.setWebFallback,
|
|
393
|
+
start: () => {},
|
|
394
|
+
stop: () => {},
|
|
395
|
+
sendCommand: () => {},
|
|
396
|
+
flip: () => {},
|
|
397
|
+
clearError: () => {}
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
if (base.webFallbackActive) {
|
|
401
|
+
return {
|
|
402
|
+
isStreaming: isStreamingWeb,
|
|
403
|
+
streamState: streamStateWeb,
|
|
404
|
+
error: base.error,
|
|
405
|
+
isNative: false,
|
|
406
|
+
webFallbackActive: true,
|
|
407
|
+
webFallbackDisabled: false,
|
|
408
|
+
setWebFallback: base.setWebFallback,
|
|
409
|
+
mediaStream: mediaStreamRef.current,
|
|
410
|
+
viewfinderRef,
|
|
411
|
+
start: webStart,
|
|
412
|
+
stop: webStop,
|
|
413
|
+
sendCommand: webSendCommand,
|
|
414
|
+
flip: webFlip,
|
|
415
|
+
clearError: base.clearError
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
return {
|
|
419
|
+
isStreaming,
|
|
420
|
+
streamState,
|
|
421
|
+
error: base.error,
|
|
422
|
+
isNative: base.isNative,
|
|
423
|
+
webFallbackActive: false,
|
|
424
|
+
webFallbackDisabled: false,
|
|
425
|
+
setWebFallback: base.setWebFallback,
|
|
426
|
+
viewfinderRef,
|
|
427
|
+
start: nativeStart,
|
|
428
|
+
stop: nativeStop,
|
|
429
|
+
sendCommand: nativeSendCommand,
|
|
430
|
+
flip: nativeFlip,
|
|
431
|
+
clearError: base.clearError
|
|
432
|
+
};
|
|
433
|
+
};
|
|
434
|
+
exports.useVideoStream = useVideoStream;
|
|
@@ -1 +1,27 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.registerNativeHandlers = exports.parseNativePayload = exports.noop = exports.createSSRUnavailable = void 0;
|
|
7
|
+
/* eslint-disable react-compiler/react-compiler, react-hooks/exhaustive-deps */
|
|
8
|
+
|
|
9
|
+
const noop = () => {};
|
|
10
|
+
exports.noop = noop;
|
|
11
|
+
const createSSRUnavailable = methodName => async () => {
|
|
12
|
+
throw new Error(`${methodName} is not available in SSR environment`);
|
|
13
|
+
};
|
|
14
|
+
exports.createSSRUnavailable = createSSRUnavailable;
|
|
15
|
+
const parseNativePayload = payload => {
|
|
16
|
+
if (payload == null) return null;
|
|
17
|
+
if (typeof payload !== "string") return payload;
|
|
18
|
+
return JSON.parse(payload);
|
|
19
|
+
};
|
|
20
|
+
exports.parseNativePayload = parseNativePayload;
|
|
21
|
+
const registerNativeHandlers = handlers => {
|
|
22
|
+
handlers.forEach(([event, handler]) => window.WebBridge.register(event, handler));
|
|
23
|
+
return () => {
|
|
24
|
+
handlers.forEach(([event]) => window.WebBridge.unregister(event));
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
exports.registerNativeHandlers = registerNativeHandlers;
|
|
@@ -1 +1,16 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var _index = require("./hooks/index.js");
|
|
7
|
+
Object.keys(_index).forEach(function (key) {
|
|
8
|
+
if (key === "default" || key === "__esModule") return;
|
|
9
|
+
if (key in exports && exports[key] === _index[key]) return;
|
|
10
|
+
Object.defineProperty(exports, key, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () {
|
|
13
|
+
return _index[key];
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.ApiCollector = void 0;
|
|
7
|
+
var _constants = require("../core/constants.js");
|
|
8
|
+
/**
|
|
2
9
|
* ApiCollector.js
|
|
3
10
|
*
|
|
4
11
|
* Instruments native API call timing — how long each @JavascriptInterface
|
|
@@ -18,5 +25,61 @@
|
|
|
18
25
|
* Blue = fast native call (<50ms) — expected for sync APIs (getDeviceInfo, haptic)
|
|
19
26
|
* Grey = medium native call (<200ms) — native work worth inspecting
|
|
20
27
|
* Red = slow native call (>200ms) — native work worth inspecting
|
|
21
|
-
*/
|
|
22
|
-
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
class ApiCollector {
|
|
31
|
+
constructor(measure, nativeToWeb) {
|
|
32
|
+
this._measure = measure;
|
|
33
|
+
this._nativeToWeb = nativeToWeb;
|
|
34
|
+
}
|
|
35
|
+
init() {
|
|
36
|
+
// No web-side observers — all events come from native buffer drain
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Called by index.js to feed the normalized perf store. */
|
|
40
|
+
setWaterfallSource(fn) {
|
|
41
|
+
this._notifyWaterfall = fn;
|
|
42
|
+
}
|
|
43
|
+
setInteractionSource(fn) {
|
|
44
|
+
this._getInteraction = fn;
|
|
45
|
+
}
|
|
46
|
+
onBatchEvent(event) {
|
|
47
|
+
if (event.type !== "api-call") return;
|
|
48
|
+
const {
|
|
49
|
+
method,
|
|
50
|
+
callId,
|
|
51
|
+
nativeStartMs,
|
|
52
|
+
nativeEndMs,
|
|
53
|
+
durationMs,
|
|
54
|
+
thread
|
|
55
|
+
} = event;
|
|
56
|
+
const startTime = this._nativeToWeb(nativeStartMs);
|
|
57
|
+
const endTime = this._nativeToWeb(nativeEndMs);
|
|
58
|
+
const interactionId = this._getInteraction?.()?.interactionIdForRange(startTime, endTime) ?? null;
|
|
59
|
+
const color = durationMs > 200 ? _constants.COLOR.ERROR : durationMs > 50 ? _constants.COLOR.SECONDARY : _constants.COLOR.PRIMARY_DARK;
|
|
60
|
+
const startMark = `${_constants.PREFIX.NATIVE_API}:${method}:start:${Math.round(startTime)}`;
|
|
61
|
+
performance.mark(startMark, {
|
|
62
|
+
startTime
|
|
63
|
+
});
|
|
64
|
+
this._notifyWaterfall?.({
|
|
65
|
+
method,
|
|
66
|
+
durationMs,
|
|
67
|
+
callId,
|
|
68
|
+
thread: thread ?? null,
|
|
69
|
+
startTime,
|
|
70
|
+
endTime,
|
|
71
|
+
sessionId: interactionId,
|
|
72
|
+
parentOperation: `Native execution: ${method}`
|
|
73
|
+
});
|
|
74
|
+
this._measure.emit(`${interactionId ? `[${interactionId}] ` : ""}Native API: ${method} - ${durationMs}ms`, startMark, endTime, {
|
|
75
|
+
interactionId,
|
|
76
|
+
parentOperation: `Native execution: ${method}`,
|
|
77
|
+
method,
|
|
78
|
+
durationMs,
|
|
79
|
+
callId,
|
|
80
|
+
thread: thread ?? null,
|
|
81
|
+
simulatorValid: false
|
|
82
|
+
}, _constants.TRACK.NATIVE_API, color);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
exports.ApiCollector = ApiCollector;
|