@thelacanians/vue-native-runtime 0.3.0 → 0.4.0
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/index.cjs +247 -53
- package/dist/index.d.cts +25 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +380 -186
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -280,6 +280,17 @@ var _NativeBridgeImpl = class _NativeBridgeImpl {
|
|
|
280
280
|
));
|
|
281
281
|
}
|
|
282
282
|
}, timeoutMs);
|
|
283
|
+
if (this.pendingCallbacks.size >= _NativeBridgeImpl.MAX_PENDING_CALLBACKS) {
|
|
284
|
+
const oldestKey = this.pendingCallbacks.keys().next().value;
|
|
285
|
+
if (oldestKey !== void 0) {
|
|
286
|
+
const oldest = this.pendingCallbacks.get(oldestKey);
|
|
287
|
+
if (oldest) {
|
|
288
|
+
clearTimeout(oldest.timeoutId);
|
|
289
|
+
oldest.reject(new Error("Callback queue full, evicting oldest pending callback"));
|
|
290
|
+
this.pendingCallbacks.delete(oldestKey);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
283
294
|
this.pendingCallbacks.set(callbackId, { resolve, reject, timeoutId });
|
|
284
295
|
this.enqueue("invokeNativeModule", [moduleName, methodName, args, callbackId]);
|
|
285
296
|
});
|
|
@@ -299,11 +310,9 @@ var _NativeBridgeImpl = class _NativeBridgeImpl {
|
|
|
299
310
|
resolveCallback(callbackId, result, error) {
|
|
300
311
|
const pending = this.pendingCallbacks.get(callbackId);
|
|
301
312
|
if (!pending) {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
);
|
|
306
|
-
}
|
|
313
|
+
console.warn(
|
|
314
|
+
`[VueNative] Received callback for unknown callbackId: ${callbackId}. This likely means the callback already timed out or was evicted. The late response has been discarded.`
|
|
315
|
+
);
|
|
307
316
|
return;
|
|
308
317
|
}
|
|
309
318
|
clearTimeout(pending.timeoutId);
|
|
@@ -368,6 +377,8 @@ var _NativeBridgeImpl = class _NativeBridgeImpl {
|
|
|
368
377
|
};
|
|
369
378
|
/** Maximum callback ID before wraparound (safe for 32-bit signed int) */
|
|
370
379
|
_NativeBridgeImpl.MAX_CALLBACK_ID = 2147483647;
|
|
380
|
+
/** Maximum number of pending callbacks before evicting the oldest */
|
|
381
|
+
_NativeBridgeImpl.MAX_PENDING_CALLBACKS = 1e3;
|
|
371
382
|
var NativeBridgeImpl = _NativeBridgeImpl;
|
|
372
383
|
if (typeof globalThis.__DEV__ === "undefined") {
|
|
373
384
|
;
|
|
@@ -640,7 +651,7 @@ var VButton = defineComponent3({
|
|
|
640
651
|
});
|
|
641
652
|
|
|
642
653
|
// src/components/VInput.ts
|
|
643
|
-
import { defineComponent as defineComponent4, h as h4 } from "@vue/runtime-core";
|
|
654
|
+
import { defineComponent as defineComponent4, h as h4, ref } from "@vue/runtime-core";
|
|
644
655
|
var VInput = defineComponent4({
|
|
645
656
|
name: "VInput",
|
|
646
657
|
props: {
|
|
@@ -682,7 +693,17 @@ var VInput = defineComponent4({
|
|
|
682
693
|
},
|
|
683
694
|
emits: ["update:modelValue", "focus", "blur", "submit"],
|
|
684
695
|
setup(props, { emit }) {
|
|
696
|
+
const isComposing = ref(false);
|
|
697
|
+
const onCompositionstart = () => {
|
|
698
|
+
isComposing.value = true;
|
|
699
|
+
};
|
|
700
|
+
const onCompositionend = (payload) => {
|
|
701
|
+
isComposing.value = false;
|
|
702
|
+
const text = typeof payload === "string" ? payload : payload?.text ?? "";
|
|
703
|
+
emit("update:modelValue", text);
|
|
704
|
+
};
|
|
685
705
|
const onChangetext = (payload) => {
|
|
706
|
+
if (isComposing.value) return;
|
|
686
707
|
const text = typeof payload === "string" ? payload : payload?.text ?? "";
|
|
687
708
|
emit("update:modelValue", text);
|
|
688
709
|
};
|
|
@@ -711,6 +732,8 @@ var VInput = defineComponent4({
|
|
|
711
732
|
accessibilityHint: props.accessibilityHint,
|
|
712
733
|
accessibilityState: props.accessibilityState,
|
|
713
734
|
onChangetext,
|
|
735
|
+
onCompositionstart,
|
|
736
|
+
onCompositionend,
|
|
714
737
|
onFocus,
|
|
715
738
|
onBlur,
|
|
716
739
|
onSubmit
|
|
@@ -823,6 +846,11 @@ var VScrollView = defineComponent7({
|
|
|
823
846
|
default: false
|
|
824
847
|
},
|
|
825
848
|
contentContainerStyle: Object,
|
|
849
|
+
/** Minimum interval in ms between scroll event emissions. Default: 16 (~60fps) */
|
|
850
|
+
scrollEventThrottle: {
|
|
851
|
+
type: Number,
|
|
852
|
+
default: 16
|
|
853
|
+
},
|
|
826
854
|
/** Whether the pull-to-refresh indicator is active */
|
|
827
855
|
refreshing: {
|
|
828
856
|
type: Boolean,
|
|
@@ -836,8 +864,13 @@ var VScrollView = defineComponent7({
|
|
|
836
864
|
},
|
|
837
865
|
emits: ["scroll", "refresh"],
|
|
838
866
|
setup(props, { slots, emit }) {
|
|
867
|
+
let lastScrollEmit = 0;
|
|
839
868
|
const onScroll = (payload) => {
|
|
840
|
-
|
|
869
|
+
const now = Date.now();
|
|
870
|
+
if (now - lastScrollEmit >= props.scrollEventThrottle) {
|
|
871
|
+
lastScrollEmit = now;
|
|
872
|
+
emit("scroll", payload);
|
|
873
|
+
}
|
|
841
874
|
};
|
|
842
875
|
const onRefresh = () => {
|
|
843
876
|
emit("refresh");
|
|
@@ -867,7 +900,7 @@ var VScrollView = defineComponent7({
|
|
|
867
900
|
});
|
|
868
901
|
|
|
869
902
|
// src/components/VImage.ts
|
|
870
|
-
import { defineComponent as defineComponent8, h as h8 } from "@vue/runtime-core";
|
|
903
|
+
import { defineComponent as defineComponent8, h as h8, ref as ref2, watch } from "@vue/runtime-core";
|
|
871
904
|
var VImage = defineComponent8({
|
|
872
905
|
name: "VImage",
|
|
873
906
|
props: {
|
|
@@ -884,13 +917,29 @@ var VImage = defineComponent8({
|
|
|
884
917
|
accessibilityState: Object
|
|
885
918
|
},
|
|
886
919
|
emits: ["load", "error"],
|
|
887
|
-
setup(props, { emit }) {
|
|
920
|
+
setup(props, { emit, expose }) {
|
|
921
|
+
const loading = ref2(true);
|
|
922
|
+
watch(
|
|
923
|
+
() => props.source?.uri,
|
|
924
|
+
() => {
|
|
925
|
+
loading.value = true;
|
|
926
|
+
}
|
|
927
|
+
);
|
|
928
|
+
const onLoad = () => {
|
|
929
|
+
loading.value = false;
|
|
930
|
+
emit("load");
|
|
931
|
+
};
|
|
932
|
+
const onError = (e) => {
|
|
933
|
+
loading.value = false;
|
|
934
|
+
emit("error", e);
|
|
935
|
+
};
|
|
936
|
+
expose({ loading });
|
|
888
937
|
return () => h8(
|
|
889
938
|
"VImage",
|
|
890
939
|
{
|
|
891
940
|
...props,
|
|
892
|
-
onLoad
|
|
893
|
-
onError
|
|
941
|
+
onLoad,
|
|
942
|
+
onError
|
|
894
943
|
}
|
|
895
944
|
);
|
|
896
945
|
}
|
|
@@ -996,8 +1045,29 @@ var VList = defineComponent12({
|
|
|
996
1045
|
},
|
|
997
1046
|
emits: ["scroll", "endReached"],
|
|
998
1047
|
setup(props, { slots, emit }) {
|
|
1048
|
+
let lastScrollEmit = 0;
|
|
1049
|
+
const onScroll = (e) => {
|
|
1050
|
+
const now = Date.now();
|
|
1051
|
+
if (now - lastScrollEmit >= 16) {
|
|
1052
|
+
lastScrollEmit = now;
|
|
1053
|
+
emit("scroll", e);
|
|
1054
|
+
}
|
|
1055
|
+
};
|
|
999
1056
|
return () => {
|
|
1000
1057
|
const items = props.data ?? [];
|
|
1058
|
+
if (typeof __DEV__ !== "undefined" && __DEV__ && items.length > 0) {
|
|
1059
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1060
|
+
for (let index = 0; index < items.length; index++) {
|
|
1061
|
+
const key = props.keyExtractor(items[index], index);
|
|
1062
|
+
if (keys.has(key)) {
|
|
1063
|
+
console.warn(
|
|
1064
|
+
`[VueNative] VList: Duplicate key "${key}" at index ${index}. Each item must have a unique key for correct reconciliation.`
|
|
1065
|
+
);
|
|
1066
|
+
break;
|
|
1067
|
+
}
|
|
1068
|
+
keys.add(key);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1001
1071
|
const children = [];
|
|
1002
1072
|
if (slots.header) {
|
|
1003
1073
|
children.push(
|
|
@@ -1035,7 +1105,7 @@ var VList = defineComponent12({
|
|
|
1035
1105
|
showsScrollIndicator: props.showsScrollIndicator,
|
|
1036
1106
|
bounces: props.bounces,
|
|
1037
1107
|
horizontal: props.horizontal,
|
|
1038
|
-
onScroll
|
|
1108
|
+
onScroll,
|
|
1039
1109
|
onEndReached: () => emit("endReached")
|
|
1040
1110
|
},
|
|
1041
1111
|
children
|
|
@@ -1045,7 +1115,7 @@ var VList = defineComponent12({
|
|
|
1045
1115
|
});
|
|
1046
1116
|
|
|
1047
1117
|
// src/components/VModal.ts
|
|
1048
|
-
import { defineComponent as defineComponent13, h as h13 } from "@vue/runtime-core";
|
|
1118
|
+
import { defineComponent as defineComponent13, h as h13, ref as ref3, watch as watch2, onUnmounted } from "@vue/runtime-core";
|
|
1049
1119
|
var VModal = defineComponent13({
|
|
1050
1120
|
name: "VModal",
|
|
1051
1121
|
props: {
|
|
@@ -1060,10 +1130,24 @@ var VModal = defineComponent13({
|
|
|
1060
1130
|
},
|
|
1061
1131
|
emits: ["dismiss"],
|
|
1062
1132
|
setup(props, { slots, emit }) {
|
|
1133
|
+
const debouncedVisible = ref3(props.visible);
|
|
1134
|
+
let visibleTimer;
|
|
1135
|
+
watch2(
|
|
1136
|
+
() => props.visible,
|
|
1137
|
+
(val) => {
|
|
1138
|
+
if (visibleTimer) clearTimeout(visibleTimer);
|
|
1139
|
+
visibleTimer = setTimeout(() => {
|
|
1140
|
+
debouncedVisible.value = val;
|
|
1141
|
+
}, 50);
|
|
1142
|
+
}
|
|
1143
|
+
);
|
|
1144
|
+
onUnmounted(() => {
|
|
1145
|
+
if (visibleTimer) clearTimeout(visibleTimer);
|
|
1146
|
+
});
|
|
1063
1147
|
return () => h13(
|
|
1064
1148
|
"VModal",
|
|
1065
1149
|
{
|
|
1066
|
-
visible:
|
|
1150
|
+
visible: debouncedVisible.value,
|
|
1067
1151
|
style: props.style,
|
|
1068
1152
|
onDismiss: () => emit("dismiss")
|
|
1069
1153
|
},
|
|
@@ -1073,7 +1157,7 @@ var VModal = defineComponent13({
|
|
|
1073
1157
|
});
|
|
1074
1158
|
|
|
1075
1159
|
// src/components/VAlertDialog.ts
|
|
1076
|
-
import { defineComponent as defineComponent14, h as h14 } from "@vue/runtime-core";
|
|
1160
|
+
import { defineComponent as defineComponent14, h as h14, ref as ref4, watch as watch3, onUnmounted as onUnmounted2 } from "@vue/runtime-core";
|
|
1077
1161
|
var VAlertDialog = defineComponent14({
|
|
1078
1162
|
name: "VAlertDialog",
|
|
1079
1163
|
props: {
|
|
@@ -1084,8 +1168,22 @@ var VAlertDialog = defineComponent14({
|
|
|
1084
1168
|
},
|
|
1085
1169
|
emits: ["confirm", "cancel", "action"],
|
|
1086
1170
|
setup(props, { emit }) {
|
|
1171
|
+
const debouncedVisible = ref4(props.visible);
|
|
1172
|
+
let visibleTimer;
|
|
1173
|
+
watch3(
|
|
1174
|
+
() => props.visible,
|
|
1175
|
+
(val) => {
|
|
1176
|
+
if (visibleTimer) clearTimeout(visibleTimer);
|
|
1177
|
+
visibleTimer = setTimeout(() => {
|
|
1178
|
+
debouncedVisible.value = val;
|
|
1179
|
+
}, 50);
|
|
1180
|
+
}
|
|
1181
|
+
);
|
|
1182
|
+
onUnmounted2(() => {
|
|
1183
|
+
if (visibleTimer) clearTimeout(visibleTimer);
|
|
1184
|
+
});
|
|
1087
1185
|
return () => h14("VAlertDialog", {
|
|
1088
|
-
visible:
|
|
1186
|
+
visible: debouncedVisible.value,
|
|
1089
1187
|
title: props.title,
|
|
1090
1188
|
message: props.message,
|
|
1091
1189
|
buttons: props.buttons,
|
|
@@ -1115,7 +1213,7 @@ var VStatusBar = defineComponent15({
|
|
|
1115
1213
|
});
|
|
1116
1214
|
|
|
1117
1215
|
// src/components/VWebView.ts
|
|
1118
|
-
import { defineComponent as defineComponent16, h as h16 } from "@vue/runtime-core";
|
|
1216
|
+
import { computed, defineComponent as defineComponent16, h as h16 } from "@vue/runtime-core";
|
|
1119
1217
|
var VWebView = defineComponent16({
|
|
1120
1218
|
name: "VWebView",
|
|
1121
1219
|
props: {
|
|
@@ -1125,8 +1223,18 @@ var VWebView = defineComponent16({
|
|
|
1125
1223
|
},
|
|
1126
1224
|
emits: ["load", "error", "message"],
|
|
1127
1225
|
setup(props, { emit }) {
|
|
1226
|
+
const sanitizedSource = computed(() => {
|
|
1227
|
+
const source = props.source;
|
|
1228
|
+
if (!source?.uri) return source;
|
|
1229
|
+
const lower = source.uri.toLowerCase().trim();
|
|
1230
|
+
if (lower.startsWith("javascript:") || lower.startsWith("data:text/html")) {
|
|
1231
|
+
console.warn("[VueNative] VWebView: Blocked potentially unsafe URI scheme");
|
|
1232
|
+
return { ...source, uri: void 0 };
|
|
1233
|
+
}
|
|
1234
|
+
return source;
|
|
1235
|
+
});
|
|
1128
1236
|
return () => h16("VWebView", {
|
|
1129
|
-
source:
|
|
1237
|
+
source: sanitizedSource.value,
|
|
1130
1238
|
style: props.style,
|
|
1131
1239
|
javaScriptEnabled: props.javaScriptEnabled,
|
|
1132
1240
|
onLoad: (e) => emit("load", e),
|
|
@@ -1590,7 +1698,7 @@ var vShow = {
|
|
|
1590
1698
|
};
|
|
1591
1699
|
|
|
1592
1700
|
// src/errorBoundary.ts
|
|
1593
|
-
import { defineComponent as defineComponent28, ref, watch, onErrorCaptured } from "@vue/runtime-core";
|
|
1701
|
+
import { defineComponent as defineComponent28, ref as ref5, watch as watch4, onErrorCaptured } from "@vue/runtime-core";
|
|
1594
1702
|
var ErrorBoundary = defineComponent28({
|
|
1595
1703
|
name: "ErrorBoundary",
|
|
1596
1704
|
props: {
|
|
@@ -1601,8 +1709,8 @@ var ErrorBoundary = defineComponent28({
|
|
|
1601
1709
|
}
|
|
1602
1710
|
},
|
|
1603
1711
|
setup(props, { slots }) {
|
|
1604
|
-
const error =
|
|
1605
|
-
const errorInfo =
|
|
1712
|
+
const error = ref5(null);
|
|
1713
|
+
const errorInfo = ref5("");
|
|
1606
1714
|
onErrorCaptured((err, _instance, info) => {
|
|
1607
1715
|
const normalizedError = err instanceof Error ? err : new Error(String(err));
|
|
1608
1716
|
error.value = normalizedError;
|
|
@@ -1616,7 +1724,7 @@ var ErrorBoundary = defineComponent28({
|
|
|
1616
1724
|
error.value = null;
|
|
1617
1725
|
errorInfo.value = "";
|
|
1618
1726
|
}
|
|
1619
|
-
|
|
1727
|
+
watch4(
|
|
1620
1728
|
() => props.resetKeys,
|
|
1621
1729
|
() => {
|
|
1622
1730
|
if (error.value) {
|
|
@@ -1772,15 +1880,33 @@ function useHaptics() {
|
|
|
1772
1880
|
}
|
|
1773
1881
|
|
|
1774
1882
|
// src/composables/useAsyncStorage.ts
|
|
1883
|
+
var writeQueues = /* @__PURE__ */ new Map();
|
|
1884
|
+
function queueWrite(key, fn) {
|
|
1885
|
+
const prev = writeQueues.get(key) ?? Promise.resolve();
|
|
1886
|
+
const next = prev.then(fn, fn);
|
|
1887
|
+
writeQueues.set(key, next);
|
|
1888
|
+
next.then(() => {
|
|
1889
|
+
if (writeQueues.get(key) === next) {
|
|
1890
|
+
writeQueues.delete(key);
|
|
1891
|
+
}
|
|
1892
|
+
});
|
|
1893
|
+
return next;
|
|
1894
|
+
}
|
|
1775
1895
|
function useAsyncStorage() {
|
|
1776
1896
|
function getItem(key) {
|
|
1777
1897
|
return NativeBridge.invokeNativeModule("AsyncStorage", "getItem", [key]);
|
|
1778
1898
|
}
|
|
1779
1899
|
function setItem(key, value) {
|
|
1780
|
-
return
|
|
1900
|
+
return queueWrite(
|
|
1901
|
+
key,
|
|
1902
|
+
() => NativeBridge.invokeNativeModule("AsyncStorage", "setItem", [key, value]).then(() => void 0)
|
|
1903
|
+
);
|
|
1781
1904
|
}
|
|
1782
1905
|
function removeItem(key) {
|
|
1783
|
-
return
|
|
1906
|
+
return queueWrite(
|
|
1907
|
+
key,
|
|
1908
|
+
() => NativeBridge.invokeNativeModule("AsyncStorage", "removeItem", [key]).then(() => void 0)
|
|
1909
|
+
);
|
|
1784
1910
|
}
|
|
1785
1911
|
function getAllKeys() {
|
|
1786
1912
|
return NativeBridge.invokeNativeModule("AsyncStorage", "getAllKeys", []);
|
|
@@ -1792,9 +1918,9 @@ function useAsyncStorage() {
|
|
|
1792
1918
|
}
|
|
1793
1919
|
|
|
1794
1920
|
// src/composables/useClipboard.ts
|
|
1795
|
-
import { ref as
|
|
1921
|
+
import { ref as ref6 } from "@vue/runtime-core";
|
|
1796
1922
|
function useClipboard() {
|
|
1797
|
-
const content =
|
|
1923
|
+
const content = ref6("");
|
|
1798
1924
|
function copy(text) {
|
|
1799
1925
|
return NativeBridge.invokeNativeModule("Clipboard", "copy", [text]).then(() => void 0);
|
|
1800
1926
|
}
|
|
@@ -1808,16 +1934,16 @@ function useClipboard() {
|
|
|
1808
1934
|
}
|
|
1809
1935
|
|
|
1810
1936
|
// src/composables/useDeviceInfo.ts
|
|
1811
|
-
import { ref as
|
|
1937
|
+
import { ref as ref7, onMounted } from "@vue/runtime-core";
|
|
1812
1938
|
function useDeviceInfo() {
|
|
1813
|
-
const model =
|
|
1814
|
-
const systemVersion =
|
|
1815
|
-
const systemName =
|
|
1816
|
-
const name =
|
|
1817
|
-
const screenWidth =
|
|
1818
|
-
const screenHeight =
|
|
1819
|
-
const scale =
|
|
1820
|
-
const isLoaded =
|
|
1939
|
+
const model = ref7("");
|
|
1940
|
+
const systemVersion = ref7("");
|
|
1941
|
+
const systemName = ref7("");
|
|
1942
|
+
const name = ref7("");
|
|
1943
|
+
const screenWidth = ref7(0);
|
|
1944
|
+
const screenHeight = ref7(0);
|
|
1945
|
+
const scale = ref7(1);
|
|
1946
|
+
const isLoaded = ref7(false);
|
|
1821
1947
|
async function fetchInfo() {
|
|
1822
1948
|
const info = await NativeBridge.invokeNativeModule("DeviceInfo", "getInfo", []);
|
|
1823
1949
|
model.value = info.model ?? "";
|
|
@@ -1846,10 +1972,10 @@ function useDeviceInfo() {
|
|
|
1846
1972
|
}
|
|
1847
1973
|
|
|
1848
1974
|
// src/composables/useKeyboard.ts
|
|
1849
|
-
import { ref as
|
|
1975
|
+
import { ref as ref8 } from "@vue/runtime-core";
|
|
1850
1976
|
function useKeyboard() {
|
|
1851
|
-
const isVisible =
|
|
1852
|
-
const height =
|
|
1977
|
+
const isVisible = ref8(false);
|
|
1978
|
+
const height = ref8(0);
|
|
1853
1979
|
function dismiss() {
|
|
1854
1980
|
return NativeBridge.invokeNativeModule("Keyboard", "dismiss", []).then(() => void 0);
|
|
1855
1981
|
}
|
|
@@ -1913,27 +2039,32 @@ function useAnimation() {
|
|
|
1913
2039
|
}
|
|
1914
2040
|
|
|
1915
2041
|
// src/composables/useNetwork.ts
|
|
1916
|
-
import { ref as
|
|
2042
|
+
import { ref as ref9, onUnmounted as onUnmounted3 } from "@vue/runtime-core";
|
|
1917
2043
|
function useNetwork() {
|
|
1918
|
-
const isConnected =
|
|
1919
|
-
const connectionType =
|
|
1920
|
-
|
|
1921
|
-
isConnected.value = status.isConnected;
|
|
1922
|
-
connectionType.value = status.connectionType;
|
|
1923
|
-
}).catch(() => {
|
|
1924
|
-
});
|
|
2044
|
+
const isConnected = ref9(true);
|
|
2045
|
+
const connectionType = ref9("unknown");
|
|
2046
|
+
let lastEventTime = 0;
|
|
1925
2047
|
const unsubscribe = NativeBridge.onGlobalEvent("network:change", (payload) => {
|
|
2048
|
+
lastEventTime = Date.now();
|
|
1926
2049
|
isConnected.value = payload.isConnected;
|
|
1927
2050
|
connectionType.value = payload.connectionType;
|
|
1928
2051
|
});
|
|
1929
|
-
|
|
2052
|
+
const initTime = Date.now();
|
|
2053
|
+
NativeBridge.invokeNativeModule("Network", "getStatus").then((status) => {
|
|
2054
|
+
if (lastEventTime <= initTime) {
|
|
2055
|
+
isConnected.value = status.isConnected;
|
|
2056
|
+
connectionType.value = status.connectionType;
|
|
2057
|
+
}
|
|
2058
|
+
}).catch(() => {
|
|
2059
|
+
});
|
|
2060
|
+
onUnmounted3(unsubscribe);
|
|
1930
2061
|
return { isConnected, connectionType };
|
|
1931
2062
|
}
|
|
1932
2063
|
|
|
1933
2064
|
// src/composables/useAppState.ts
|
|
1934
|
-
import { ref as
|
|
2065
|
+
import { ref as ref10, onUnmounted as onUnmounted4 } from "@vue/runtime-core";
|
|
1935
2066
|
function useAppState() {
|
|
1936
|
-
const state =
|
|
2067
|
+
const state = ref10("active");
|
|
1937
2068
|
NativeBridge.invokeNativeModule("AppState", "getState").then((s) => {
|
|
1938
2069
|
state.value = s;
|
|
1939
2070
|
}).catch(() => {
|
|
@@ -1941,7 +2072,7 @@ function useAppState() {
|
|
|
1941
2072
|
const unsubscribe = NativeBridge.onGlobalEvent("appState:change", (payload) => {
|
|
1942
2073
|
state.value = payload.state;
|
|
1943
2074
|
});
|
|
1944
|
-
|
|
2075
|
+
onUnmounted4(unsubscribe);
|
|
1945
2076
|
return { state };
|
|
1946
2077
|
}
|
|
1947
2078
|
|
|
@@ -1976,27 +2107,45 @@ function usePermissions() {
|
|
|
1976
2107
|
}
|
|
1977
2108
|
|
|
1978
2109
|
// src/composables/useGeolocation.ts
|
|
1979
|
-
import { ref as
|
|
2110
|
+
import { ref as ref11, onUnmounted as onUnmounted5 } from "@vue/runtime-core";
|
|
1980
2111
|
function useGeolocation() {
|
|
1981
|
-
const coords =
|
|
1982
|
-
const error =
|
|
2112
|
+
const coords = ref11(null);
|
|
2113
|
+
const error = ref11(null);
|
|
1983
2114
|
let watchId = null;
|
|
1984
2115
|
async function getCurrentPosition() {
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
2116
|
+
try {
|
|
2117
|
+
error.value = null;
|
|
2118
|
+
const result = await NativeBridge.invokeNativeModule("Geolocation", "getCurrentPosition");
|
|
2119
|
+
coords.value = result;
|
|
2120
|
+
return result;
|
|
2121
|
+
} catch (e) {
|
|
2122
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
2123
|
+
error.value = msg;
|
|
2124
|
+
throw e;
|
|
2125
|
+
}
|
|
1988
2126
|
}
|
|
1989
2127
|
async function watchPosition() {
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2128
|
+
try {
|
|
2129
|
+
error.value = null;
|
|
2130
|
+
const id = await NativeBridge.invokeNativeModule("Geolocation", "watchPosition");
|
|
2131
|
+
watchId = id;
|
|
2132
|
+
const unsubscribe = NativeBridge.onGlobalEvent("location:update", (payload) => {
|
|
2133
|
+
coords.value = payload;
|
|
2134
|
+
});
|
|
2135
|
+
const unsubscribeError = NativeBridge.onGlobalEvent("location:error", (payload) => {
|
|
2136
|
+
error.value = payload.message;
|
|
2137
|
+
});
|
|
2138
|
+
onUnmounted5(() => {
|
|
2139
|
+
unsubscribe();
|
|
2140
|
+
unsubscribeError();
|
|
2141
|
+
if (watchId !== null) clearWatch(watchId);
|
|
2142
|
+
});
|
|
2143
|
+
return id;
|
|
2144
|
+
} catch (e) {
|
|
2145
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
2146
|
+
error.value = msg;
|
|
2147
|
+
throw e;
|
|
2148
|
+
}
|
|
2000
2149
|
}
|
|
2001
2150
|
async function clearWatch(id) {
|
|
2002
2151
|
await NativeBridge.invokeNativeModule("Geolocation", "clearWatch", [id]);
|
|
@@ -2006,7 +2155,7 @@ function useGeolocation() {
|
|
|
2006
2155
|
}
|
|
2007
2156
|
|
|
2008
2157
|
// src/composables/useCamera.ts
|
|
2009
|
-
import { onUnmounted as
|
|
2158
|
+
import { onUnmounted as onUnmounted6 } from "@vue/runtime-core";
|
|
2010
2159
|
function useCamera() {
|
|
2011
2160
|
const qrCleanups = [];
|
|
2012
2161
|
async function launchCamera(options = {}) {
|
|
@@ -2029,7 +2178,7 @@ function useCamera() {
|
|
|
2029
2178
|
qrCleanups.push(unsubscribe);
|
|
2030
2179
|
return unsubscribe;
|
|
2031
2180
|
}
|
|
2032
|
-
|
|
2181
|
+
onUnmounted6(() => {
|
|
2033
2182
|
NativeBridge.invokeNativeModule("Camera", "stopQRScan").catch(() => {
|
|
2034
2183
|
});
|
|
2035
2184
|
qrCleanups.forEach((fn) => fn());
|
|
@@ -2039,10 +2188,10 @@ function useCamera() {
|
|
|
2039
2188
|
}
|
|
2040
2189
|
|
|
2041
2190
|
// src/composables/useNotifications.ts
|
|
2042
|
-
import { ref as
|
|
2191
|
+
import { ref as ref12, onUnmounted as onUnmounted7 } from "@vue/runtime-core";
|
|
2043
2192
|
function useNotifications() {
|
|
2044
|
-
const isGranted =
|
|
2045
|
-
const pushToken =
|
|
2193
|
+
const isGranted = ref12(false);
|
|
2194
|
+
const pushToken = ref12(null);
|
|
2046
2195
|
async function requestPermission() {
|
|
2047
2196
|
const granted = await NativeBridge.invokeNativeModule("Notifications", "requestPermission");
|
|
2048
2197
|
isGranted.value = granted;
|
|
@@ -2062,7 +2211,7 @@ function useNotifications() {
|
|
|
2062
2211
|
}
|
|
2063
2212
|
function onNotification(handler) {
|
|
2064
2213
|
const unsubscribe = NativeBridge.onGlobalEvent("notification:received", handler);
|
|
2065
|
-
|
|
2214
|
+
onUnmounted7(unsubscribe);
|
|
2066
2215
|
return unsubscribe;
|
|
2067
2216
|
}
|
|
2068
2217
|
async function registerForPush() {
|
|
@@ -2076,12 +2225,12 @@ function useNotifications() {
|
|
|
2076
2225
|
pushToken.value = payload.token;
|
|
2077
2226
|
handler(payload.token);
|
|
2078
2227
|
});
|
|
2079
|
-
|
|
2228
|
+
onUnmounted7(unsubscribe);
|
|
2080
2229
|
return unsubscribe;
|
|
2081
2230
|
}
|
|
2082
2231
|
function onPushReceived(handler) {
|
|
2083
2232
|
const unsubscribe = NativeBridge.onGlobalEvent("push:received", handler);
|
|
2084
|
-
|
|
2233
|
+
onUnmounted7(unsubscribe);
|
|
2085
2234
|
return unsubscribe;
|
|
2086
2235
|
}
|
|
2087
2236
|
return {
|
|
@@ -2117,7 +2266,7 @@ function useBiometry() {
|
|
|
2117
2266
|
}
|
|
2118
2267
|
|
|
2119
2268
|
// src/composables/useHttp.ts
|
|
2120
|
-
import { ref as
|
|
2269
|
+
import { ref as ref13, onUnmounted as onUnmounted8 } from "@vue/runtime-core";
|
|
2121
2270
|
function useHttp(config = {}) {
|
|
2122
2271
|
if (config.pins && Object.keys(config.pins).length > 0) {
|
|
2123
2272
|
const configurePins = globalThis.__VN_configurePins;
|
|
@@ -2127,8 +2276,12 @@ function useHttp(config = {}) {
|
|
|
2127
2276
|
NativeBridge.invokeNativeModule("Http", "configurePins", [config.pins]);
|
|
2128
2277
|
}
|
|
2129
2278
|
}
|
|
2130
|
-
const loading =
|
|
2131
|
-
const error =
|
|
2279
|
+
const loading = ref13(false);
|
|
2280
|
+
const error = ref13(null);
|
|
2281
|
+
let isMounted = true;
|
|
2282
|
+
onUnmounted8(() => {
|
|
2283
|
+
isMounted = false;
|
|
2284
|
+
});
|
|
2132
2285
|
async function request(method, url, options = {}) {
|
|
2133
2286
|
const fullUrl = config.baseURL ? `${config.baseURL}${url}` : url;
|
|
2134
2287
|
loading.value = true;
|
|
@@ -2148,6 +2301,9 @@ function useHttp(config = {}) {
|
|
|
2148
2301
|
}
|
|
2149
2302
|
const response = await fetch(fullUrl, fetchOptions);
|
|
2150
2303
|
const data = await response.json();
|
|
2304
|
+
if (!isMounted) {
|
|
2305
|
+
return { data, status: response.status, ok: response.ok, headers: {} };
|
|
2306
|
+
}
|
|
2151
2307
|
return {
|
|
2152
2308
|
data,
|
|
2153
2309
|
status: response.status,
|
|
@@ -2156,10 +2312,14 @@ function useHttp(config = {}) {
|
|
|
2156
2312
|
};
|
|
2157
2313
|
} catch (e) {
|
|
2158
2314
|
const msg = e instanceof Error ? e.message : String(e);
|
|
2159
|
-
|
|
2315
|
+
if (isMounted) {
|
|
2316
|
+
error.value = msg;
|
|
2317
|
+
}
|
|
2160
2318
|
throw e;
|
|
2161
2319
|
} finally {
|
|
2162
|
-
|
|
2320
|
+
if (isMounted) {
|
|
2321
|
+
loading.value = false;
|
|
2322
|
+
}
|
|
2163
2323
|
}
|
|
2164
2324
|
}
|
|
2165
2325
|
return {
|
|
@@ -2174,10 +2334,10 @@ function useHttp(config = {}) {
|
|
|
2174
2334
|
}
|
|
2175
2335
|
|
|
2176
2336
|
// src/composables/useColorScheme.ts
|
|
2177
|
-
import { ref as
|
|
2337
|
+
import { ref as ref14, onUnmounted as onUnmounted9 } from "@vue/runtime-core";
|
|
2178
2338
|
function useColorScheme() {
|
|
2179
|
-
const colorScheme =
|
|
2180
|
-
const isDark =
|
|
2339
|
+
const colorScheme = ref14("light");
|
|
2340
|
+
const isDark = ref14(false);
|
|
2181
2341
|
const unsubscribe = NativeBridge.onGlobalEvent(
|
|
2182
2342
|
"colorScheme:change",
|
|
2183
2343
|
(payload) => {
|
|
@@ -2185,20 +2345,24 @@ function useColorScheme() {
|
|
|
2185
2345
|
isDark.value = payload.colorScheme === "dark";
|
|
2186
2346
|
}
|
|
2187
2347
|
);
|
|
2188
|
-
|
|
2348
|
+
onUnmounted9(unsubscribe);
|
|
2189
2349
|
return { colorScheme, isDark };
|
|
2190
2350
|
}
|
|
2191
2351
|
|
|
2192
2352
|
// src/composables/useBackHandler.ts
|
|
2193
|
-
import { onMounted as onMounted2, onUnmounted as
|
|
2353
|
+
import { onMounted as onMounted2, onUnmounted as onUnmounted10 } from "@vue/runtime-core";
|
|
2194
2354
|
function useBackHandler(handler) {
|
|
2195
2355
|
let unsubscribe = null;
|
|
2196
2356
|
onMounted2(() => {
|
|
2197
2357
|
unsubscribe = NativeBridge.onGlobalEvent("hardware:backPress", () => {
|
|
2198
|
-
handler();
|
|
2358
|
+
const handled = handler();
|
|
2359
|
+
if (!handled) {
|
|
2360
|
+
NativeBridge.invokeNativeModule("BackHandler", "exitApp", []).catch(() => {
|
|
2361
|
+
});
|
|
2362
|
+
}
|
|
2199
2363
|
});
|
|
2200
2364
|
});
|
|
2201
|
-
|
|
2365
|
+
onUnmounted10(() => {
|
|
2202
2366
|
unsubscribe?.();
|
|
2203
2367
|
unsubscribe = null;
|
|
2204
2368
|
});
|
|
@@ -2222,10 +2386,10 @@ function useSecureStorage() {
|
|
|
2222
2386
|
}
|
|
2223
2387
|
|
|
2224
2388
|
// src/composables/useI18n.ts
|
|
2225
|
-
import { ref as
|
|
2389
|
+
import { ref as ref15, onMounted as onMounted3 } from "@vue/runtime-core";
|
|
2226
2390
|
function useI18n() {
|
|
2227
|
-
const isRTL =
|
|
2228
|
-
const locale =
|
|
2391
|
+
const isRTL = ref15(false);
|
|
2392
|
+
const locale = ref15("en");
|
|
2229
2393
|
onMounted3(async () => {
|
|
2230
2394
|
try {
|
|
2231
2395
|
const info = await NativeBridge.invokeNativeModule("DeviceInfo", "getDeviceInfo", []);
|
|
@@ -2246,11 +2410,11 @@ function usePlatform() {
|
|
|
2246
2410
|
}
|
|
2247
2411
|
|
|
2248
2412
|
// src/composables/useDimensions.ts
|
|
2249
|
-
import { ref as
|
|
2413
|
+
import { ref as ref16, onMounted as onMounted4, onUnmounted as onUnmounted11 } from "@vue/runtime-core";
|
|
2250
2414
|
function useDimensions() {
|
|
2251
|
-
const width =
|
|
2252
|
-
const height =
|
|
2253
|
-
const scale =
|
|
2415
|
+
const width = ref16(0);
|
|
2416
|
+
const height = ref16(0);
|
|
2417
|
+
const scale = ref16(1);
|
|
2254
2418
|
onMounted4(async () => {
|
|
2255
2419
|
try {
|
|
2256
2420
|
const info = await NativeBridge.invokeNativeModule("DeviceInfo", "getInfo", []);
|
|
@@ -2265,12 +2429,12 @@ function useDimensions() {
|
|
|
2265
2429
|
if (payload.height != null) height.value = payload.height;
|
|
2266
2430
|
if (payload.scale != null) scale.value = payload.scale;
|
|
2267
2431
|
});
|
|
2268
|
-
|
|
2432
|
+
onUnmounted11(cleanup);
|
|
2269
2433
|
return { width, height, scale };
|
|
2270
2434
|
}
|
|
2271
2435
|
|
|
2272
2436
|
// src/composables/useWebSocket.ts
|
|
2273
|
-
import { ref as
|
|
2437
|
+
import { ref as ref17, onUnmounted as onUnmounted12 } from "@vue/runtime-core";
|
|
2274
2438
|
var connectionCounter = 0;
|
|
2275
2439
|
function useWebSocket(url, options = {}) {
|
|
2276
2440
|
const {
|
|
@@ -2280,11 +2444,13 @@ function useWebSocket(url, options = {}) {
|
|
|
2280
2444
|
reconnectInterval = 1e3
|
|
2281
2445
|
} = options;
|
|
2282
2446
|
const connectionId = `ws_${++connectionCounter}_${Date.now()}`;
|
|
2283
|
-
const status =
|
|
2284
|
-
const lastMessage =
|
|
2285
|
-
const error =
|
|
2447
|
+
const status = ref17("CLOSED");
|
|
2448
|
+
const lastMessage = ref17(null);
|
|
2449
|
+
const error = ref17(null);
|
|
2286
2450
|
let reconnectAttempts = 0;
|
|
2287
2451
|
let reconnectTimer = null;
|
|
2452
|
+
const MAX_PENDING_MESSAGES = 100;
|
|
2453
|
+
const pendingMessages = [];
|
|
2288
2454
|
const unsubscribers = [];
|
|
2289
2455
|
unsubscribers.push(
|
|
2290
2456
|
NativeBridge.onGlobalEvent("websocket:open", (payload) => {
|
|
@@ -2292,6 +2458,12 @@ function useWebSocket(url, options = {}) {
|
|
|
2292
2458
|
status.value = "OPEN";
|
|
2293
2459
|
error.value = null;
|
|
2294
2460
|
reconnectAttempts = 0;
|
|
2461
|
+
while (pendingMessages.length > 0) {
|
|
2462
|
+
const msg = pendingMessages.shift();
|
|
2463
|
+
NativeBridge.invokeNativeModule("WebSocket", "send", [connectionId, msg]).catch((err) => {
|
|
2464
|
+
error.value = err.message;
|
|
2465
|
+
});
|
|
2466
|
+
}
|
|
2295
2467
|
})
|
|
2296
2468
|
);
|
|
2297
2469
|
unsubscribers.push(
|
|
@@ -2306,9 +2478,10 @@ function useWebSocket(url, options = {}) {
|
|
|
2306
2478
|
status.value = "CLOSED";
|
|
2307
2479
|
if (autoReconnect && reconnectAttempts < maxReconnectAttempts && payload.code !== 1e3) {
|
|
2308
2480
|
reconnectAttempts++;
|
|
2481
|
+
const backoffMs = reconnectInterval * Math.pow(2, reconnectAttempts - 1);
|
|
2309
2482
|
reconnectTimer = setTimeout(() => {
|
|
2310
2483
|
open();
|
|
2311
|
-
},
|
|
2484
|
+
}, backoffMs);
|
|
2312
2485
|
}
|
|
2313
2486
|
})
|
|
2314
2487
|
);
|
|
@@ -2328,8 +2501,17 @@ function useWebSocket(url, options = {}) {
|
|
|
2328
2501
|
});
|
|
2329
2502
|
}
|
|
2330
2503
|
function send(data) {
|
|
2331
|
-
if (status.value !== "OPEN") return;
|
|
2332
2504
|
const message = typeof data === "string" ? data : JSON.stringify(data);
|
|
2505
|
+
if (status.value !== "OPEN") {
|
|
2506
|
+
if (pendingMessages.length >= MAX_PENDING_MESSAGES) {
|
|
2507
|
+
pendingMessages.shift();
|
|
2508
|
+
if (__DEV__) {
|
|
2509
|
+
console.warn("[VueNative] WebSocket pending message queue full, dropping oldest message");
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
pendingMessages.push(message);
|
|
2513
|
+
return;
|
|
2514
|
+
}
|
|
2333
2515
|
NativeBridge.invokeNativeModule("WebSocket", "send", [connectionId, message]).catch((err) => {
|
|
2334
2516
|
error.value = err.message;
|
|
2335
2517
|
});
|
|
@@ -2349,7 +2531,7 @@ function useWebSocket(url, options = {}) {
|
|
|
2349
2531
|
if (autoConnect) {
|
|
2350
2532
|
open();
|
|
2351
2533
|
}
|
|
2352
|
-
|
|
2534
|
+
onUnmounted12(() => {
|
|
2353
2535
|
if (reconnectTimer) {
|
|
2354
2536
|
clearTimeout(reconnectTimer);
|
|
2355
2537
|
}
|
|
@@ -2418,12 +2600,12 @@ function useFileSystem() {
|
|
|
2418
2600
|
}
|
|
2419
2601
|
|
|
2420
2602
|
// src/composables/useSensors.ts
|
|
2421
|
-
import { ref as
|
|
2603
|
+
import { ref as ref18, onUnmounted as onUnmounted13 } from "@vue/runtime-core";
|
|
2422
2604
|
function useAccelerometer(options = {}) {
|
|
2423
|
-
const x =
|
|
2424
|
-
const y =
|
|
2425
|
-
const z =
|
|
2426
|
-
const isAvailable =
|
|
2605
|
+
const x = ref18(0);
|
|
2606
|
+
const y = ref18(0);
|
|
2607
|
+
const z = ref18(0);
|
|
2608
|
+
const isAvailable = ref18(false);
|
|
2427
2609
|
let running = false;
|
|
2428
2610
|
let unsubscribe = null;
|
|
2429
2611
|
NativeBridge.invokeNativeModule("Sensors", "isAvailable", ["accelerometer"]).then((result) => {
|
|
@@ -2451,16 +2633,16 @@ function useAccelerometer(options = {}) {
|
|
|
2451
2633
|
NativeBridge.invokeNativeModule("Sensors", "stopAccelerometer").catch(() => {
|
|
2452
2634
|
});
|
|
2453
2635
|
}
|
|
2454
|
-
|
|
2636
|
+
onUnmounted13(() => {
|
|
2455
2637
|
stop();
|
|
2456
2638
|
});
|
|
2457
2639
|
return { x, y, z, isAvailable, start, stop };
|
|
2458
2640
|
}
|
|
2459
2641
|
function useGyroscope(options = {}) {
|
|
2460
|
-
const x =
|
|
2461
|
-
const y =
|
|
2462
|
-
const z =
|
|
2463
|
-
const isAvailable =
|
|
2642
|
+
const x = ref18(0);
|
|
2643
|
+
const y = ref18(0);
|
|
2644
|
+
const z = ref18(0);
|
|
2645
|
+
const isAvailable = ref18(false);
|
|
2464
2646
|
let running = false;
|
|
2465
2647
|
let unsubscribe = null;
|
|
2466
2648
|
NativeBridge.invokeNativeModule("Sensors", "isAvailable", ["gyroscope"]).then((result) => {
|
|
@@ -2488,20 +2670,20 @@ function useGyroscope(options = {}) {
|
|
|
2488
2670
|
NativeBridge.invokeNativeModule("Sensors", "stopGyroscope").catch(() => {
|
|
2489
2671
|
});
|
|
2490
2672
|
}
|
|
2491
|
-
|
|
2673
|
+
onUnmounted13(() => {
|
|
2492
2674
|
stop();
|
|
2493
2675
|
});
|
|
2494
2676
|
return { x, y, z, isAvailable, start, stop };
|
|
2495
2677
|
}
|
|
2496
2678
|
|
|
2497
2679
|
// src/composables/useAudio.ts
|
|
2498
|
-
import { ref as
|
|
2680
|
+
import { ref as ref19, onUnmounted as onUnmounted14 } from "@vue/runtime-core";
|
|
2499
2681
|
function useAudio() {
|
|
2500
|
-
const duration =
|
|
2501
|
-
const position =
|
|
2502
|
-
const isPlaying =
|
|
2503
|
-
const isRecording =
|
|
2504
|
-
const error =
|
|
2682
|
+
const duration = ref19(0);
|
|
2683
|
+
const position = ref19(0);
|
|
2684
|
+
const isPlaying = ref19(false);
|
|
2685
|
+
const isRecording = ref19(false);
|
|
2686
|
+
const error = ref19(null);
|
|
2505
2687
|
const unsubProgress = NativeBridge.onGlobalEvent("audio:progress", (payload) => {
|
|
2506
2688
|
position.value = payload.currentTime ?? 0;
|
|
2507
2689
|
duration.value = payload.duration ?? 0;
|
|
@@ -2514,7 +2696,7 @@ function useAudio() {
|
|
|
2514
2696
|
error.value = payload.message ?? "Unknown audio error";
|
|
2515
2697
|
isPlaying.value = false;
|
|
2516
2698
|
});
|
|
2517
|
-
|
|
2699
|
+
onUnmounted14(() => {
|
|
2518
2700
|
unsubProgress();
|
|
2519
2701
|
unsubComplete();
|
|
2520
2702
|
unsubError();
|
|
@@ -2593,9 +2775,9 @@ function useAudio() {
|
|
|
2593
2775
|
}
|
|
2594
2776
|
|
|
2595
2777
|
// src/composables/useDatabase.ts
|
|
2596
|
-
import { ref as
|
|
2778
|
+
import { ref as ref20, onUnmounted as onUnmounted15 } from "@vue/runtime-core";
|
|
2597
2779
|
function useDatabase(name = "default") {
|
|
2598
|
-
const isOpen =
|
|
2780
|
+
const isOpen = ref20(false);
|
|
2599
2781
|
let opened = false;
|
|
2600
2782
|
async function ensureOpen() {
|
|
2601
2783
|
if (opened) return;
|
|
@@ -2613,22 +2795,22 @@ function useDatabase(name = "default") {
|
|
|
2613
2795
|
}
|
|
2614
2796
|
async function transaction(callback) {
|
|
2615
2797
|
await ensureOpen();
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
await NativeBridge.invokeNativeModule("Database", "executeTransaction", [name, statements.splice(0)]);
|
|
2798
|
+
await NativeBridge.invokeNativeModule("Database", "execute", [name, "BEGIN TRANSACTION", []]);
|
|
2799
|
+
try {
|
|
2800
|
+
const ctx = {
|
|
2801
|
+
execute: async (sql, params) => {
|
|
2802
|
+
return NativeBridge.invokeNativeModule("Database", "execute", [name, sql, params ?? []]);
|
|
2803
|
+
},
|
|
2804
|
+
query: async (sql, params) => {
|
|
2805
|
+
return NativeBridge.invokeNativeModule("Database", "query", [name, sql, params ?? []]);
|
|
2625
2806
|
}
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2807
|
+
};
|
|
2808
|
+
await callback(ctx);
|
|
2809
|
+
await NativeBridge.invokeNativeModule("Database", "execute", [name, "COMMIT", []]);
|
|
2810
|
+
} catch (err) {
|
|
2811
|
+
await NativeBridge.invokeNativeModule("Database", "execute", [name, "ROLLBACK", []]).catch(() => {
|
|
2812
|
+
});
|
|
2813
|
+
throw err;
|
|
2632
2814
|
}
|
|
2633
2815
|
}
|
|
2634
2816
|
async function close() {
|
|
@@ -2637,7 +2819,7 @@ function useDatabase(name = "default") {
|
|
|
2637
2819
|
opened = false;
|
|
2638
2820
|
isOpen.value = false;
|
|
2639
2821
|
}
|
|
2640
|
-
|
|
2822
|
+
onUnmounted15(() => {
|
|
2641
2823
|
if (opened) {
|
|
2642
2824
|
NativeBridge.invokeNativeModule("Database", "close", [name]).catch(() => {
|
|
2643
2825
|
});
|
|
@@ -2649,12 +2831,12 @@ function useDatabase(name = "default") {
|
|
|
2649
2831
|
}
|
|
2650
2832
|
|
|
2651
2833
|
// src/composables/usePerformance.ts
|
|
2652
|
-
import { ref as
|
|
2834
|
+
import { ref as ref21, onUnmounted as onUnmounted16 } from "@vue/runtime-core";
|
|
2653
2835
|
function usePerformance() {
|
|
2654
|
-
const isProfiling =
|
|
2655
|
-
const fps =
|
|
2656
|
-
const memoryMB =
|
|
2657
|
-
const bridgeOps =
|
|
2836
|
+
const isProfiling = ref21(false);
|
|
2837
|
+
const fps = ref21(0);
|
|
2838
|
+
const memoryMB = ref21(0);
|
|
2839
|
+
const bridgeOps = ref21(0);
|
|
2658
2840
|
let unsubscribe = null;
|
|
2659
2841
|
function handleMetrics(payload) {
|
|
2660
2842
|
fps.value = payload.fps ?? 0;
|
|
@@ -2679,7 +2861,7 @@ function usePerformance() {
|
|
|
2679
2861
|
async function getMetrics() {
|
|
2680
2862
|
return NativeBridge.invokeNativeModule("Performance", "getMetrics", []);
|
|
2681
2863
|
}
|
|
2682
|
-
|
|
2864
|
+
onUnmounted16(() => {
|
|
2683
2865
|
if (isProfiling.value) {
|
|
2684
2866
|
NativeBridge.invokeNativeModule("Performance", "stopProfiling", []).catch(() => {
|
|
2685
2867
|
});
|
|
@@ -2702,10 +2884,10 @@ function usePerformance() {
|
|
|
2702
2884
|
}
|
|
2703
2885
|
|
|
2704
2886
|
// src/composables/useSharedElementTransition.ts
|
|
2705
|
-
import { ref as
|
|
2887
|
+
import { ref as ref22, onUnmounted as onUnmounted17 } from "@vue/runtime-core";
|
|
2706
2888
|
var sharedElementRegistry = /* @__PURE__ */ new Map();
|
|
2707
2889
|
function useSharedElementTransition(elementId) {
|
|
2708
|
-
const viewId =
|
|
2890
|
+
const viewId = ref22(null);
|
|
2709
2891
|
function register(nativeViewId) {
|
|
2710
2892
|
viewId.value = nativeViewId;
|
|
2711
2893
|
sharedElementRegistry.set(elementId, nativeViewId);
|
|
@@ -2714,7 +2896,7 @@ function useSharedElementTransition(elementId) {
|
|
|
2714
2896
|
viewId.value = null;
|
|
2715
2897
|
sharedElementRegistry.delete(elementId);
|
|
2716
2898
|
}
|
|
2717
|
-
|
|
2899
|
+
onUnmounted17(() => {
|
|
2718
2900
|
unregister();
|
|
2719
2901
|
});
|
|
2720
2902
|
return {
|
|
@@ -2738,11 +2920,11 @@ function clearSharedElementRegistry() {
|
|
|
2738
2920
|
}
|
|
2739
2921
|
|
|
2740
2922
|
// src/composables/useIAP.ts
|
|
2741
|
-
import { ref as
|
|
2923
|
+
import { ref as ref23, onUnmounted as onUnmounted18 } from "@vue/runtime-core";
|
|
2742
2924
|
function useIAP() {
|
|
2743
|
-
const products =
|
|
2744
|
-
const isReady =
|
|
2745
|
-
const error =
|
|
2925
|
+
const products = ref23([]);
|
|
2926
|
+
const isReady = ref23(false);
|
|
2927
|
+
const error = ref23(null);
|
|
2746
2928
|
const cleanups = [];
|
|
2747
2929
|
const unsubscribe = NativeBridge.onGlobalEvent("iap:transactionUpdate", (payload) => {
|
|
2748
2930
|
if (payload.state === "failed" && payload.error) {
|
|
@@ -2799,7 +2981,7 @@ function useIAP() {
|
|
|
2799
2981
|
cleanups.push(unsub);
|
|
2800
2982
|
return unsub;
|
|
2801
2983
|
}
|
|
2802
|
-
|
|
2984
|
+
onUnmounted18(() => {
|
|
2803
2985
|
cleanups.forEach((fn) => fn());
|
|
2804
2986
|
cleanups.length = 0;
|
|
2805
2987
|
});
|
|
@@ -2816,11 +2998,11 @@ function useIAP() {
|
|
|
2816
2998
|
}
|
|
2817
2999
|
|
|
2818
3000
|
// src/composables/useAppleSignIn.ts
|
|
2819
|
-
import { ref as
|
|
3001
|
+
import { ref as ref24, onUnmounted as onUnmounted19 } from "@vue/runtime-core";
|
|
2820
3002
|
function useAppleSignIn() {
|
|
2821
|
-
const user =
|
|
2822
|
-
const isAuthenticated =
|
|
2823
|
-
const error =
|
|
3003
|
+
const user = ref24(null);
|
|
3004
|
+
const isAuthenticated = ref24(false);
|
|
3005
|
+
const error = ref24(null);
|
|
2824
3006
|
const cleanups = [];
|
|
2825
3007
|
const unsubscribe = NativeBridge.onGlobalEvent("auth:appleCredentialRevoked", () => {
|
|
2826
3008
|
user.value = null;
|
|
@@ -2858,7 +3040,7 @@ function useAppleSignIn() {
|
|
|
2858
3040
|
error.value = String(err);
|
|
2859
3041
|
}
|
|
2860
3042
|
}
|
|
2861
|
-
|
|
3043
|
+
onUnmounted19(() => {
|
|
2862
3044
|
cleanups.forEach((fn) => fn());
|
|
2863
3045
|
cleanups.length = 0;
|
|
2864
3046
|
});
|
|
@@ -2866,11 +3048,11 @@ function useAppleSignIn() {
|
|
|
2866
3048
|
}
|
|
2867
3049
|
|
|
2868
3050
|
// src/composables/useGoogleSignIn.ts
|
|
2869
|
-
import { ref as
|
|
3051
|
+
import { ref as ref25, onUnmounted as onUnmounted20 } from "@vue/runtime-core";
|
|
2870
3052
|
function useGoogleSignIn(clientId) {
|
|
2871
|
-
const user =
|
|
2872
|
-
const isAuthenticated =
|
|
2873
|
-
const error =
|
|
3053
|
+
const user = ref25(null);
|
|
3054
|
+
const isAuthenticated = ref25(false);
|
|
3055
|
+
const error = ref25(null);
|
|
2874
3056
|
const cleanups = [];
|
|
2875
3057
|
NativeBridge.invokeNativeModule("SocialAuth", "getCurrentUser", ["google"]).then((result) => {
|
|
2876
3058
|
if (result && result.userId) {
|
|
@@ -2903,7 +3085,7 @@ function useGoogleSignIn(clientId) {
|
|
|
2903
3085
|
error.value = String(err);
|
|
2904
3086
|
}
|
|
2905
3087
|
}
|
|
2906
|
-
|
|
3088
|
+
onUnmounted20(() => {
|
|
2907
3089
|
cleanups.forEach((fn) => fn());
|
|
2908
3090
|
cleanups.length = 0;
|
|
2909
3091
|
});
|
|
@@ -2911,17 +3093,17 @@ function useGoogleSignIn(clientId) {
|
|
|
2911
3093
|
}
|
|
2912
3094
|
|
|
2913
3095
|
// src/composables/useBackgroundTask.ts
|
|
2914
|
-
import { ref as
|
|
3096
|
+
import { ref as ref26, onUnmounted as onUnmounted21 } from "@vue/runtime-core";
|
|
2915
3097
|
function useBackgroundTask() {
|
|
2916
3098
|
const taskHandlers = /* @__PURE__ */ new Map();
|
|
2917
|
-
const defaultHandler =
|
|
3099
|
+
const defaultHandler = ref26(null);
|
|
2918
3100
|
const unsubscribe = NativeBridge.onGlobalEvent("background:taskExecute", (payload) => {
|
|
2919
3101
|
const handler = taskHandlers.get(payload.taskId) || defaultHandler.value;
|
|
2920
3102
|
if (handler) {
|
|
2921
3103
|
handler(payload.taskId);
|
|
2922
3104
|
}
|
|
2923
3105
|
});
|
|
2924
|
-
|
|
3106
|
+
onUnmounted21(unsubscribe);
|
|
2925
3107
|
function registerTask(taskId) {
|
|
2926
3108
|
return NativeBridge.invokeNativeModule("BackgroundTask", "registerTask", [taskId]).then(() => void 0);
|
|
2927
3109
|
}
|
|
@@ -2960,20 +3142,20 @@ function useBackgroundTask() {
|
|
|
2960
3142
|
}
|
|
2961
3143
|
|
|
2962
3144
|
// src/composables/useOTAUpdate.ts
|
|
2963
|
-
import { ref as
|
|
3145
|
+
import { ref as ref27, onUnmounted as onUnmounted22 } from "@vue/runtime-core";
|
|
2964
3146
|
function useOTAUpdate(serverUrl) {
|
|
2965
|
-
const currentVersion =
|
|
2966
|
-
const availableVersion =
|
|
2967
|
-
const downloadProgress =
|
|
2968
|
-
const isChecking =
|
|
2969
|
-
const isDownloading =
|
|
2970
|
-
const status =
|
|
2971
|
-
const error =
|
|
3147
|
+
const currentVersion = ref27("embedded");
|
|
3148
|
+
const availableVersion = ref27(null);
|
|
3149
|
+
const downloadProgress = ref27(0);
|
|
3150
|
+
const isChecking = ref27(false);
|
|
3151
|
+
const isDownloading = ref27(false);
|
|
3152
|
+
const status = ref27("idle");
|
|
3153
|
+
const error = ref27(null);
|
|
2972
3154
|
let lastUpdateInfo = null;
|
|
2973
3155
|
const unsubscribe = NativeBridge.onGlobalEvent("ota:downloadProgress", (payload) => {
|
|
2974
3156
|
downloadProgress.value = payload.progress;
|
|
2975
3157
|
});
|
|
2976
|
-
|
|
3158
|
+
onUnmounted22(unsubscribe);
|
|
2977
3159
|
NativeBridge.invokeNativeModule("OTA", "getCurrentVersion", []).then((info) => {
|
|
2978
3160
|
currentVersion.value = info.version;
|
|
2979
3161
|
}).catch(() => {
|
|
@@ -3017,6 +3199,8 @@ function useOTAUpdate(serverUrl) {
|
|
|
3017
3199
|
await NativeBridge.invokeNativeModule("OTA", "downloadUpdate", [downloadUrl, expectedHash || ""]);
|
|
3018
3200
|
status.value = "ready";
|
|
3019
3201
|
} catch (err) {
|
|
3202
|
+
await NativeBridge.invokeNativeModule("OTA", "cleanupPartialDownload", []).catch(() => {
|
|
3203
|
+
});
|
|
3020
3204
|
error.value = err?.message || String(err);
|
|
3021
3205
|
status.value = "error";
|
|
3022
3206
|
throw err;
|
|
@@ -3025,7 +3209,17 @@ function useOTAUpdate(serverUrl) {
|
|
|
3025
3209
|
}
|
|
3026
3210
|
}
|
|
3027
3211
|
async function applyUpdate() {
|
|
3212
|
+
if (status.value !== "ready") {
|
|
3213
|
+
throw new Error("No update ready to apply. Call downloadUpdate() first.");
|
|
3214
|
+
}
|
|
3028
3215
|
error.value = null;
|
|
3216
|
+
try {
|
|
3217
|
+
await NativeBridge.invokeNativeModule("OTA", "verifyBundle", []);
|
|
3218
|
+
} catch (err) {
|
|
3219
|
+
status.value = "error";
|
|
3220
|
+
error.value = "Bundle verification failed: " + (err?.message || String(err));
|
|
3221
|
+
throw err;
|
|
3222
|
+
}
|
|
3029
3223
|
try {
|
|
3030
3224
|
await NativeBridge.invokeNativeModule("OTA", "applyUpdate", []);
|
|
3031
3225
|
const info = await NativeBridge.invokeNativeModule("OTA", "getCurrentVersion", []);
|
|
@@ -3073,13 +3267,13 @@ function useOTAUpdate(serverUrl) {
|
|
|
3073
3267
|
}
|
|
3074
3268
|
|
|
3075
3269
|
// src/composables/useBluetooth.ts
|
|
3076
|
-
import { ref as
|
|
3270
|
+
import { ref as ref28, onUnmounted as onUnmounted23 } from "@vue/runtime-core";
|
|
3077
3271
|
function useBluetooth() {
|
|
3078
|
-
const devices =
|
|
3079
|
-
const connectedDevice =
|
|
3080
|
-
const isScanning =
|
|
3081
|
-
const isAvailable =
|
|
3082
|
-
const error =
|
|
3272
|
+
const devices = ref28([]);
|
|
3273
|
+
const connectedDevice = ref28(null);
|
|
3274
|
+
const isScanning = ref28(false);
|
|
3275
|
+
const isAvailable = ref28(false);
|
|
3276
|
+
const error = ref28(null);
|
|
3083
3277
|
const cleanups = [];
|
|
3084
3278
|
NativeBridge.invokeNativeModule("Bluetooth", "getState").then((state) => {
|
|
3085
3279
|
isAvailable.value = state === "poweredOn";
|
|
@@ -3158,7 +3352,7 @@ function useBluetooth() {
|
|
|
3158
3352
|
]);
|
|
3159
3353
|
};
|
|
3160
3354
|
}
|
|
3161
|
-
|
|
3355
|
+
onUnmounted23(() => {
|
|
3162
3356
|
if (isScanning.value) {
|
|
3163
3357
|
NativeBridge.invokeNativeModule("Bluetooth", "stopScan").catch(() => {
|
|
3164
3358
|
});
|
|
@@ -3183,10 +3377,10 @@ function useBluetooth() {
|
|
|
3183
3377
|
}
|
|
3184
3378
|
|
|
3185
3379
|
// src/composables/useCalendar.ts
|
|
3186
|
-
import { ref as
|
|
3380
|
+
import { ref as ref29 } from "@vue/runtime-core";
|
|
3187
3381
|
function useCalendar() {
|
|
3188
|
-
const hasAccess =
|
|
3189
|
-
const error =
|
|
3382
|
+
const hasAccess = ref29(false);
|
|
3383
|
+
const error = ref29(null);
|
|
3190
3384
|
async function requestAccess() {
|
|
3191
3385
|
try {
|
|
3192
3386
|
const result = await NativeBridge.invokeNativeModule("Calendar", "requestAccess");
|
|
@@ -3219,10 +3413,10 @@ function useCalendar() {
|
|
|
3219
3413
|
}
|
|
3220
3414
|
|
|
3221
3415
|
// src/composables/useContacts.ts
|
|
3222
|
-
import { ref as
|
|
3416
|
+
import { ref as ref30 } from "@vue/runtime-core";
|
|
3223
3417
|
function useContacts() {
|
|
3224
|
-
const hasAccess =
|
|
3225
|
-
const error =
|
|
3418
|
+
const hasAccess = ref30(false);
|
|
3419
|
+
const error = ref30(null);
|
|
3226
3420
|
async function requestAccess() {
|
|
3227
3421
|
try {
|
|
3228
3422
|
const result = await NativeBridge.invokeNativeModule("Contacts", "requestAccess");
|