@ateam-ai-mobile/expo 0.1.5 → 0.1.8

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.
Files changed (179) hide show
  1. package/android/build.gradle +16 -0
  2. package/android/src/main/java/expo/modules/adavision/AdaVisionModule.kt +75 -0
  3. package/dist/attachmentCache-DhQTqi2E.d.mts +18 -0
  4. package/dist/attachmentCache-DhQTqi2E.d.ts +18 -0
  5. package/dist/bootstrap.d.mts +95 -0
  6. package/dist/bootstrap.d.ts +95 -0
  7. package/dist/bootstrap.js +2991 -0
  8. package/dist/bootstrap.js.map +1 -0
  9. package/dist/bootstrap.mjs +66 -0
  10. package/dist/bootstrap.mjs.map +1 -0
  11. package/dist/chunk-4BMWVN25.mjs +91 -0
  12. package/dist/chunk-4BMWVN25.mjs.map +1 -0
  13. package/dist/chunk-6LXF3JVX.mjs +96 -0
  14. package/dist/chunk-6LXF3JVX.mjs.map +1 -0
  15. package/dist/chunk-7FWYEHN5.mjs +203 -0
  16. package/dist/chunk-7FWYEHN5.mjs.map +1 -0
  17. package/dist/chunk-C7M5WAHA.mjs +1798 -0
  18. package/dist/chunk-C7M5WAHA.mjs.map +1 -0
  19. package/dist/chunk-FF6ZZZXH.mjs +71 -0
  20. package/dist/chunk-FF6ZZZXH.mjs.map +1 -0
  21. package/dist/chunk-GF2MPTAB.mjs +647 -0
  22. package/dist/chunk-GF2MPTAB.mjs.map +1 -0
  23. package/dist/chunk-J6XRNX7P.mjs +19 -0
  24. package/dist/chunk-J6XRNX7P.mjs.map +1 -0
  25. package/dist/chunk-KOXF2FZM.mjs +92 -0
  26. package/dist/chunk-KOXF2FZM.mjs.map +1 -0
  27. package/dist/chunk-L4V7OCJ3.mjs +71 -0
  28. package/dist/chunk-L4V7OCJ3.mjs.map +1 -0
  29. package/dist/chunk-PCAEUX2N.mjs +67 -0
  30. package/dist/chunk-PCAEUX2N.mjs.map +1 -0
  31. package/dist/chunk-WMJKH4XE.mjs +34 -0
  32. package/dist/chunk-WMJKH4XE.mjs.map +1 -0
  33. package/dist/chunk-XQSY6MHP.mjs +213 -0
  34. package/dist/chunk-XQSY6MHP.mjs.map +1 -0
  35. package/dist/chunk-Z5AI2SXX.mjs +1810 -0
  36. package/dist/chunk-Z5AI2SXX.mjs.map +1 -0
  37. package/dist/createBridge.js +41 -10
  38. package/dist/createBridge.js.map +1 -1
  39. package/dist/createBridge.mjs +7 -1
  40. package/dist/createBridge.mjs.map +1 -1
  41. package/dist/device/createDeviceProvider.d.mts +23 -0
  42. package/dist/device/createDeviceProvider.d.ts +23 -0
  43. package/dist/device/createDeviceProvider.js +1228 -0
  44. package/dist/device/createDeviceProvider.js.map +1 -0
  45. package/dist/device/createDeviceProvider.mjs +19 -0
  46. package/dist/device/createDeviceProvider.mjs.map +1 -0
  47. package/dist/device-bridge/collectors/appEngagement.d.mts +10 -0
  48. package/dist/device-bridge/collectors/appEngagement.d.ts +10 -0
  49. package/dist/device-bridge/collectors/appEngagement.js +128 -0
  50. package/dist/device-bridge/collectors/appEngagement.js.map +1 -0
  51. package/dist/device-bridge/collectors/appEngagement.mjs +12 -0
  52. package/dist/device-bridge/collectors/appEngagement.mjs.map +1 -0
  53. package/dist/device-bridge/collectors/health.d.mts +24 -0
  54. package/dist/device-bridge/collectors/health.d.ts +24 -0
  55. package/dist/device-bridge/collectors/health.js +238 -0
  56. package/dist/device-bridge/collectors/health.js.map +1 -0
  57. package/dist/device-bridge/collectors/health.mjs +18 -0
  58. package/dist/device-bridge/collectors/health.mjs.map +1 -0
  59. package/dist/device-bridge/cookies.d.mts +49 -0
  60. package/dist/device-bridge/cookies.d.ts +49 -0
  61. package/dist/device-bridge/cookies.js +90 -0
  62. package/dist/device-bridge/cookies.js.map +1 -0
  63. package/dist/device-bridge/cookies.mjs +14 -0
  64. package/dist/device-bridge/cookies.mjs.map +1 -0
  65. package/dist/device-bridge/index.d.mts +495 -0
  66. package/dist/device-bridge/index.d.ts +495 -0
  67. package/dist/device-bridge/index.js +2121 -0
  68. package/dist/device-bridge/index.js.map +1 -0
  69. package/dist/device-bridge/index.mjs +34 -0
  70. package/dist/device-bridge/index.mjs.map +1 -0
  71. package/dist/device-bridge/nfc.d.mts +30 -0
  72. package/dist/device-bridge/nfc.d.ts +30 -0
  73. package/dist/device-bridge/nfc.js +109 -0
  74. package/dist/device-bridge/nfc.js.map +1 -0
  75. package/dist/device-bridge/nfc.mjs +14 -0
  76. package/dist/device-bridge/nfc.mjs.map +1 -0
  77. package/dist/index.d.mts +509 -18
  78. package/dist/index.d.ts +509 -18
  79. package/dist/index.js +1706 -6
  80. package/dist/index.js.map +1 -1
  81. package/dist/index.mjs +24 -194
  82. package/dist/index.mjs.map +1 -1
  83. package/dist/maps/index.d.mts +56 -0
  84. package/dist/maps/index.d.ts +56 -0
  85. package/dist/maps/index.js +95 -0
  86. package/dist/maps/index.js.map +1 -0
  87. package/dist/maps/index.mjs +17 -0
  88. package/dist/maps/index.mjs.map +1 -0
  89. package/dist/oauth/expoOAuth.d.mts +18 -0
  90. package/dist/oauth/expoOAuth.d.ts +18 -0
  91. package/dist/oauth/expoOAuth.js +102 -0
  92. package/dist/oauth/expoOAuth.js.map +1 -0
  93. package/dist/oauth/expoOAuth.mjs +8 -0
  94. package/dist/oauth/expoOAuth.mjs.map +1 -0
  95. package/dist/types-BRanJYTn.d.mts +138 -0
  96. package/dist/types-BRanJYTn.d.ts +138 -0
  97. package/dist/vision/index.d.mts +83 -0
  98. package/dist/vision/index.d.ts +83 -0
  99. package/dist/vision/index.js +101 -0
  100. package/dist/vision/index.js.map +1 -0
  101. package/dist/vision/index.mjs +28 -0
  102. package/dist/vision/index.mjs.map +1 -0
  103. package/expo-module.config.json +9 -0
  104. package/ios/AdaMaps/AdaMapsModule.swift +180 -0
  105. package/ios/AdaMaps.podspec +25 -0
  106. package/ios/AdaVision.podspec +32 -0
  107. package/ios/AdaVisionModule.swift +486 -0
  108. package/ios/Resources/yolov8n-oiv7.mlmodelc/analytics/coremldata.bin +0 -0
  109. package/ios/Resources/yolov8n-oiv7.mlmodelc/coremldata.bin +0 -0
  110. package/ios/Resources/yolov8n-oiv7.mlmodelc/metadata.json +773 -0
  111. package/ios/Resources/yolov8n-oiv7.mlmodelc/model0/analytics/coremldata.bin +0 -0
  112. package/ios/Resources/yolov8n-oiv7.mlmodelc/model0/coremldata.bin +0 -0
  113. package/ios/Resources/yolov8n-oiv7.mlmodelc/model0/model.mil +720 -0
  114. package/ios/Resources/yolov8n-oiv7.mlmodelc/model0/weights/weight.bin +0 -0
  115. package/ios/Resources/yolov8n-oiv7.mlmodelc/model1/coremldata.bin +0 -0
  116. package/package.json +113 -7
  117. package/src/args.ts +56 -0
  118. package/src/bootstrap.ts +159 -0
  119. package/src/camera/CameraTaskHost.tsx +175 -0
  120. package/src/camera/cameraTasks.ts +129 -0
  121. package/src/createBridge.ts +3 -1
  122. package/src/device/createDeviceProvider.ts +917 -0
  123. package/src/device-bridge/actions/calendar-actions.ts +217 -0
  124. package/src/device-bridge/actions/dnd.ts +74 -0
  125. package/src/device-bridge/actions/health-actions.ts +58 -0
  126. package/src/device-bridge/actions/index.ts +12 -0
  127. package/src/device-bridge/actions/messaging.ts +74 -0
  128. package/src/device-bridge/actions/navigation.ts +88 -0
  129. package/src/device-bridge/actions/queue-poller.ts +151 -0
  130. package/src/device-bridge/background.ts +137 -0
  131. package/src/device-bridge/biometrics.ts +64 -0
  132. package/src/device-bridge/capabilities.ts +218 -0
  133. package/src/device-bridge/collectors/appEngagement.ts +120 -0
  134. package/src/device-bridge/collectors/battery.ts +83 -0
  135. package/src/device-bridge/collectors/calendar.ts +162 -0
  136. package/src/device-bridge/collectors/camera.ts +27 -0
  137. package/src/device-bridge/collectors/connectivity.ts +60 -0
  138. package/src/device-bridge/collectors/contacts.ts +200 -0
  139. package/src/device-bridge/collectors/health.ts +299 -0
  140. package/src/device-bridge/collectors/index.ts +12 -0
  141. package/src/device-bridge/collectors/location.ts +236 -0
  142. package/src/device-bridge/collectors/mood.ts +141 -0
  143. package/src/device-bridge/collectors/notifications.ts +70 -0
  144. package/src/device-bridge/cookies.ts +89 -0
  145. package/src/device-bridge/dynamic-connector.ts +422 -0
  146. package/src/device-bridge/index.ts +467 -0
  147. package/src/device-bridge/nfc.ts +85 -0
  148. package/src/device-bridge/plugin.ts +71 -0
  149. package/src/device-bridge/relay-client.ts +237 -0
  150. package/src/device-bridge/scanner.ts +42 -0
  151. package/src/device-bridge/sharing.ts +35 -0
  152. package/src/device-bridge/types.ts +326 -0
  153. package/src/device-state/activityClassifier.ts +151 -0
  154. package/src/device-state/activityEngine.ts +252 -0
  155. package/src/device-state/collectors.ts +35 -0
  156. package/src/device-state/domains/activity.ts +93 -0
  157. package/src/device-state/domains/capability.ts +60 -0
  158. package/src/device-state/domains/connectivity.ts +60 -0
  159. package/src/device-state/domains/deviceContext.ts +57 -0
  160. package/src/device-state/domains/interaction.ts +60 -0
  161. package/src/device-state/domains/spatial.ts +367 -0
  162. package/src/device-state/domains/visual.ts +121 -0
  163. package/src/device-state/events.ts +49 -0
  164. package/src/device-state/headingSource.ts +119 -0
  165. package/src/device-state/index.ts +78 -0
  166. package/src/device-state/quality.ts +60 -0
  167. package/src/device-state/replay.ts +285 -0
  168. package/src/device-state/spatialEvents.ts +300 -0
  169. package/src/device-state/turnDetector.ts +121 -0
  170. package/src/device-state/visualEngine.ts +341 -0
  171. package/src/geo.ts +23 -0
  172. package/src/haptics.ts +4 -0
  173. package/src/index.ts +37 -0
  174. package/src/maps/index.ts +81 -0
  175. package/src/maps/normalize.ts +225 -0
  176. package/src/oauth/expoOAuth.tsx +113 -0
  177. package/src/vision/analysis.js +80 -0
  178. package/src/vision/index.ts +146 -0
  179. package/src/vision/ring.js +35 -0
@@ -0,0 +1,647 @@
1
+ import {
2
+ describe,
3
+ detectObjects,
4
+ isSupported,
5
+ qualityById,
6
+ readText
7
+ } from "./chunk-PCAEUX2N.mjs";
8
+ import {
9
+ cameraTasks
10
+ } from "./chunk-6LXF3JVX.mjs";
11
+ import {
12
+ cookies_exports,
13
+ init_cookies
14
+ } from "./chunk-FF6ZZZXH.mjs";
15
+ import {
16
+ biometrics_exports,
17
+ scanner_exports,
18
+ sharing_exports
19
+ } from "./chunk-Z5AI2SXX.mjs";
20
+ import {
21
+ init_nfc,
22
+ nfc_exports
23
+ } from "./chunk-4BMWVN25.mjs";
24
+ import {
25
+ coordinateArg,
26
+ countArg,
27
+ fractionArg,
28
+ isSupported as isSupported2,
29
+ mapsFailure,
30
+ missingReason,
31
+ refuseArgument,
32
+ reverseGeocode,
33
+ route,
34
+ search,
35
+ searchArgs,
36
+ shown,
37
+ toMapsPlaces,
38
+ toMapsRoute,
39
+ toReverseGeocodedPlace
40
+ } from "./chunk-7FWYEHN5.mjs";
41
+ import {
42
+ __toCommonJS
43
+ } from "./chunk-WMJKH4XE.mjs";
44
+
45
+ // src/device/createDeviceProvider.ts
46
+ import * as Haptics from "expo-haptics";
47
+ import * as ExpoLocation from "expo-location";
48
+ import * as ImagePicker from "expo-image-picker";
49
+ import * as Notifications from "expo-notifications";
50
+ import * as DocumentPicker from "expo-document-picker";
51
+ import * as FS from "expo-file-system";
52
+ import * as SQLite from "expo-sqlite";
53
+ import AsyncStorage from "@react-native-async-storage/async-storage";
54
+ function getDeviceCookies() {
55
+ try {
56
+ return init_cookies(), __toCommonJS(cookies_exports);
57
+ } catch {
58
+ return null;
59
+ }
60
+ }
61
+ function getDeviceNfc() {
62
+ try {
63
+ return init_nfc(), __toCommonJS(nfc_exports);
64
+ } catch {
65
+ return null;
66
+ }
67
+ }
68
+ var CapabilityUnavailableError = class extends Error {
69
+ constructor(capability, reason) {
70
+ super(reason || `${capability} is not yet implemented. Coming in Phase 2.`);
71
+ this.code = "UNAVAILABLE";
72
+ this.name = "CapabilityUnavailableError";
73
+ }
74
+ };
75
+ function stubApi(capability) {
76
+ return new Proxy({}, {
77
+ get(_target, prop) {
78
+ if (typeof prop === "string") {
79
+ return () => {
80
+ throw new CapabilityUnavailableError(capability);
81
+ };
82
+ }
83
+ }
84
+ });
85
+ }
86
+ function createLocationAPI() {
87
+ const ensurePermission = async () => {
88
+ const existing = await ExpoLocation.getForegroundPermissionsAsync();
89
+ if (existing.status === "granted") return;
90
+ const asked = await ExpoLocation.requestForegroundPermissionsAsync();
91
+ if (asked.status !== "granted") {
92
+ throw new Error(
93
+ "Location permission was not granted. Enable it for this app in Settings > Privacy > Location Services."
94
+ );
95
+ }
96
+ };
97
+ return {
98
+ async getCurrent(opts) {
99
+ await ensurePermission();
100
+ const fix = await ExpoLocation.getCurrentPositionAsync({
101
+ accuracy: opts?.accuracy === "high" ? ExpoLocation.Accuracy.High : ExpoLocation.Accuracy.Balanced
102
+ });
103
+ return {
104
+ latitude: fix.coords.latitude,
105
+ longitude: fix.coords.longitude,
106
+ altitude: fix.coords.altitude ?? void 0
107
+ };
108
+ },
109
+ watchPosition(cb) {
110
+ let subscription = null;
111
+ let cancelled = false;
112
+ void (async () => {
113
+ try {
114
+ await ensurePermission();
115
+ if (cancelled) return;
116
+ subscription = await ExpoLocation.watchPositionAsync(
117
+ { accuracy: ExpoLocation.Accuracy.Balanced },
118
+ (fix) => cb({ latitude: fix.coords.latitude, longitude: fix.coords.longitude })
119
+ );
120
+ if (cancelled) {
121
+ subscription?.remove();
122
+ subscription = null;
123
+ }
124
+ } catch (err) {
125
+ console.warn("[location] watchPosition failed:", err?.message || String(err));
126
+ }
127
+ })();
128
+ return () => {
129
+ cancelled = true;
130
+ subscription?.remove();
131
+ subscription = null;
132
+ };
133
+ }
134
+ };
135
+ }
136
+ function createCameraAPI() {
137
+ const ensurePermission = async () => {
138
+ const existing = await ImagePicker.getCameraPermissionsAsync();
139
+ if (existing.granted) return;
140
+ const asked = await ImagePicker.requestCameraPermissionsAsync();
141
+ if (!asked.granted) {
142
+ throw new Error(
143
+ "Camera permission was not granted. Enable it for this app in Settings > Privacy > Camera."
144
+ );
145
+ }
146
+ };
147
+ return {
148
+ async takePhoto(opts) {
149
+ await ensurePermission();
150
+ const res = await ImagePicker.launchCameraAsync({
151
+ quality: opts?.quality ?? 0.7,
152
+ cameraType: opts?.facing === "front" ? ImagePicker.CameraType.front : ImagePicker.CameraType.back
153
+ });
154
+ if (res.canceled || !res.assets?.[0]) {
155
+ throw new Error("No photo taken \u2014 the camera was dismissed.");
156
+ }
157
+ const a = res.assets[0];
158
+ return { uri: a.uri, width: a.width, height: a.height };
159
+ },
160
+ async scanBarcode(opts) {
161
+ throw new CapabilityUnavailableError(
162
+ "camera.scanBarcode",
163
+ "Use native.scanner.scanOnce() instead \u2014 scanning needs a mounted camera, which this call cannot provide. Same arguments, and it returns { data, format }." + (opts?.formats?.length ? " Pass your formats through to scanOnce." : "")
164
+ );
165
+ },
166
+ async recordVideo(opts) {
167
+ return cameraTasks.run("record", {
168
+ maxDurationMs: opts?.maxDurationMs,
169
+ withAudio: opts?.withAudio ?? false
170
+ });
171
+ },
172
+ async pickImage(opts) {
173
+ const existing = await ImagePicker.getMediaLibraryPermissionsAsync();
174
+ if (!existing.granted) {
175
+ const asked = await ImagePicker.requestMediaLibraryPermissionsAsync();
176
+ if (!asked.granted) {
177
+ throw new Error(
178
+ "Photo library permission was not granted. Enable it for this app in Settings > Privacy > Photos."
179
+ );
180
+ }
181
+ }
182
+ const res = await ImagePicker.launchImageLibraryAsync({
183
+ allowsMultipleSelection: !!opts?.multiple
184
+ });
185
+ if (res.canceled) return [];
186
+ return (res.assets || []).map((a) => ({ uri: a.uri }));
187
+ }
188
+ };
189
+ }
190
+ var _pluginDbs = /* @__PURE__ */ new Map();
191
+ function openPluginDb(file) {
192
+ const existing = _pluginDbs.get(file);
193
+ if (existing) return existing;
194
+ const opened = SQLite.openDatabaseAsync(file);
195
+ _pluginDbs.set(file, opened);
196
+ return opened;
197
+ }
198
+ function sqlLeadingKeyword(sql) {
199
+ let s = String(sql);
200
+ for (; ; ) {
201
+ const before = s;
202
+ s = s.replace(/^\s+/, "");
203
+ if (s.startsWith("--")) {
204
+ const nl = s.indexOf("\n");
205
+ s = nl === -1 ? "" : s.slice(nl + 1);
206
+ } else if (s.startsWith("/*")) {
207
+ const end = s.indexOf("*/");
208
+ s = end === -1 ? "" : s.slice(end + 2);
209
+ }
210
+ if (s === before) break;
211
+ }
212
+ const m = s.match(/^[A-Za-z]+/);
213
+ return m ? m[0].toUpperCase() : "";
214
+ }
215
+ function createStorageAPI(pluginId) {
216
+ const ns = encodeURIComponent(pluginId);
217
+ const key = (k) => `@plugin:${ns}:${k}`;
218
+ const dbFile = `plugin-storage-${ns}.db`;
219
+ return {
220
+ get: (k) => AsyncStorage.getItem(key(k)),
221
+ set: (k, v) => AsyncStorage.setItem(key(k), v),
222
+ delete: (k) => AsyncStorage.removeItem(key(k)),
223
+ db: {
224
+ async execute(sql, params) {
225
+ const verb = sqlLeadingKeyword(sql);
226
+ if (verb === "ATTACH" || verb === "DETACH" || verb === "VACUUM") {
227
+ throw new CapabilityUnavailableError(
228
+ "storage.db",
229
+ `SQL '${verb}' is not permitted: a plugin's storage is confined to its own database and cannot reach another file.`
230
+ );
231
+ }
232
+ const db = await openPluginDb(dbFile);
233
+ const returnsRows = verb === "SELECT" || verb === "PRAGMA" || verb === "WITH";
234
+ if (returnsRows) {
235
+ const rows = await db.getAllAsync(sql, params ?? []);
236
+ return { rows, changes: 0 };
237
+ }
238
+ const res = await db.runAsync(sql, params ?? []);
239
+ return { rows: [], changes: res.changes ?? 0 };
240
+ }
241
+ }
242
+ };
243
+ }
244
+ async function clearAllPluginData() {
245
+ try {
246
+ const keys = await AsyncStorage.getAllKeys();
247
+ const mine = keys.filter((k) => k.startsWith("@plugin:"));
248
+ if (mine.length) await AsyncStorage.multiRemove(mine);
249
+ } catch (e) {
250
+ console.warn("[adas] clearAllPluginData: KV clear failed:", e?.message || e);
251
+ }
252
+ try {
253
+ for (const [, p] of _pluginDbs) {
254
+ try {
255
+ const db = await p;
256
+ await db.closeAsync?.();
257
+ } catch {
258
+ }
259
+ }
260
+ _pluginDbs.clear();
261
+ const sqliteDir = new FS.Directory(FS.Paths.document, "SQLite");
262
+ if (sqliteDir.exists) {
263
+ for (const entry of sqliteDir.list()) {
264
+ if (/^plugin-storage-.*\.db$/.test(String(entry.name ?? ""))) {
265
+ try {
266
+ entry.delete();
267
+ } catch {
268
+ }
269
+ }
270
+ }
271
+ }
272
+ } catch (e) {
273
+ console.warn("[adas] clearAllPluginData: SQLite clear failed:", e?.message || e);
274
+ }
275
+ try {
276
+ const dir = new FS.Directory(FS.Paths.document, "plugin-files");
277
+ if (dir.exists) dir.delete();
278
+ } catch (e) {
279
+ console.warn("[adas] clearAllPluginData: file sandbox clear failed:", e?.message || e);
280
+ }
281
+ }
282
+ function createNotificationsAPI() {
283
+ return {
284
+ async schedule({ title, body, trigger }) {
285
+ const perm = await Notifications.getPermissionsAsync();
286
+ if (!perm.granted) {
287
+ const asked = await Notifications.requestPermissionsAsync();
288
+ if (!asked.granted) {
289
+ throw new Error(
290
+ "Notification permission was not granted. Enable it for this app in Settings > Notifications."
291
+ );
292
+ }
293
+ }
294
+ const when = typeof trigger?.seconds === "number" ? { type: "timeInterval", seconds: trigger.seconds, repeats: false } : trigger?.date ? { type: "date", date: new Date(trigger.date) } : null;
295
+ if (!when) {
296
+ throw new Error("schedule() needs trigger.seconds or trigger.date.");
297
+ }
298
+ return Notifications.scheduleNotificationAsync({
299
+ content: { title, body },
300
+ trigger: when
301
+ });
302
+ },
303
+ cancel: (id) => Notifications.cancelScheduledNotificationAsync(id),
304
+ onReceived(cb) {
305
+ const sub = Notifications.addNotificationReceivedListener((n) => {
306
+ cb({
307
+ id: n.request.identifier,
308
+ title: n.request.content.title || "",
309
+ body: n.request.content.body || "",
310
+ data: n.request.content.data
311
+ });
312
+ });
313
+ return () => sub.remove();
314
+ }
315
+ };
316
+ }
317
+ function createFileSystemAPI(pluginId) {
318
+ let _root = null;
319
+ const rootDir = () => _root ?? (_root = new FS.Directory(FS.Paths.document, "plugin-files", pluginId));
320
+ const resolve = (p) => {
321
+ const root = rootDir();
322
+ const file = new FS.File(root, p);
323
+ if (!file.uri.startsWith(root.uri)) {
324
+ throw new CapabilityUnavailableError(
325
+ "fileSystem",
326
+ `Path escapes the plugin's storage area: ${p}. Plugin files live under plugin-files/ and paths cannot traverse out of it.`
327
+ );
328
+ }
329
+ return file;
330
+ };
331
+ return {
332
+ async readFile(path) {
333
+ const file = resolve(path);
334
+ if (!file.exists) {
335
+ throw new CapabilityUnavailableError(
336
+ "fileSystem.readFile",
337
+ `No such file: ${path}. Nothing was read.`
338
+ );
339
+ }
340
+ return file.text();
341
+ },
342
+ async writeFile(path, content) {
343
+ const file = resolve(path);
344
+ const parent = file.parentDirectory;
345
+ if (!parent.exists) parent.create({ intermediates: true });
346
+ if (!file.exists) file.create();
347
+ file.write(content);
348
+ },
349
+ async pickDocument(opts) {
350
+ const res = await DocumentPicker.getDocumentAsync({
351
+ type: opts?.types?.length ? opts.types : "*/*",
352
+ copyToCacheDirectory: true
353
+ });
354
+ if (res.canceled || !res.assets?.[0]) {
355
+ throw new Error("No document chosen \u2014 the picker was dismissed.");
356
+ }
357
+ const a = res.assets[0];
358
+ return { uri: a.uri, name: a.name, size: a.size ?? 0 };
359
+ }
360
+ };
361
+ }
362
+ function createHapticsAPI() {
363
+ return {
364
+ impact(style) {
365
+ const map = {
366
+ light: Haptics.ImpactFeedbackStyle.Light,
367
+ medium: Haptics.ImpactFeedbackStyle.Medium,
368
+ heavy: Haptics.ImpactFeedbackStyle.Heavy
369
+ };
370
+ Haptics.impactAsync(map[style]);
371
+ },
372
+ notification(type) {
373
+ const map = {
374
+ success: Haptics.NotificationFeedbackType.Success,
375
+ warning: Haptics.NotificationFeedbackType.Warning,
376
+ error: Haptics.NotificationFeedbackType.Error
377
+ };
378
+ Haptics.notificationAsync(map[type]);
379
+ },
380
+ // Shorthand for notification('error'). Plugins call this; it was never
381
+ // implemented, and optional chaining meant the failure the user was meant
382
+ // to FEEL simply did not happen.
383
+ error() {
384
+ Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
385
+ },
386
+ selection() {
387
+ Haptics.selectionAsync();
388
+ }
389
+ };
390
+ }
391
+ function createConnectivityAPI(reachabilityUrl) {
392
+ let online = true;
393
+ const listeners = /* @__PURE__ */ new Set();
394
+ let interval = null;
395
+ const checkOnline = async () => {
396
+ if (!reachabilityUrl) return true;
397
+ try {
398
+ const res = await fetch(reachabilityUrl, {
399
+ method: "HEAD",
400
+ signal: AbortSignal.timeout(5e3)
401
+ });
402
+ return res.ok;
403
+ } catch {
404
+ return false;
405
+ }
406
+ };
407
+ const startPolling = () => {
408
+ if (!reachabilityUrl) return;
409
+ if (interval) return;
410
+ interval = setInterval(async () => {
411
+ const newState = await checkOnline();
412
+ if (newState !== online) {
413
+ online = newState;
414
+ listeners.forEach((cb) => cb(online));
415
+ }
416
+ }, 3e4);
417
+ };
418
+ return {
419
+ isOnline() {
420
+ return online;
421
+ },
422
+ onChange(cb) {
423
+ listeners.add(cb);
424
+ startPolling();
425
+ return () => {
426
+ listeners.delete(cb);
427
+ if (listeners.size === 0 && interval) {
428
+ clearInterval(interval);
429
+ interval = null;
430
+ }
431
+ };
432
+ }
433
+ };
434
+ }
435
+ function createCookiesAPI() {
436
+ return {
437
+ async get(url) {
438
+ const mod = getDeviceCookies();
439
+ if (!mod) throw new CapabilityUnavailableError("cookies (native module not available \u2014 use a dev build)");
440
+ const list = await mod.get(url, true);
441
+ return list;
442
+ },
443
+ async clear(_url) {
444
+ const mod = getDeviceCookies();
445
+ if (!mod) throw new CapabilityUnavailableError("cookies (native module not available \u2014 use a dev build)");
446
+ const r = await mod.clearAll();
447
+ return { ok: r.ok };
448
+ }
449
+ };
450
+ }
451
+ function createBiometricsAPIv2() {
452
+ return {
453
+ capabilities: () => biometrics_exports.capabilities(),
454
+ authenticate: (opts) => biometrics_exports.authenticate(opts)
455
+ };
456
+ }
457
+ function createSharingAPI() {
458
+ return {
459
+ isAvailable: () => sharing_exports.isAvailable(),
460
+ shareFile: (fileUri, opts) => sharing_exports.shareFile(fileUri, opts)
461
+ };
462
+ }
463
+ function createScannerAPI() {
464
+ return {
465
+ requestPermissions: () => scanner_exports.requestPermissions(),
466
+ // Raises the shared camera surface and settles on the first code read.
467
+ // The plugin mounts nothing — that lifecycle is owned once, by
468
+ // CameraTaskHost, instead of by every plugin that wants to scan.
469
+ scanOnce: (opts) => cameraTasks.run("scan", {
470
+ formats: opts?.formats,
471
+ timeoutMs: opts?.timeoutMs
472
+ })
473
+ };
474
+ }
475
+ function createNfcAPI() {
476
+ return {
477
+ async isSupported() {
478
+ const mod = getDeviceNfc();
479
+ if (!mod) return false;
480
+ return mod.isSupported();
481
+ },
482
+ async isEnabled() {
483
+ const mod = getDeviceNfc();
484
+ if (!mod) return false;
485
+ return mod.isEnabled();
486
+ },
487
+ readOnce(timeoutMs) {
488
+ const mod = getDeviceNfc();
489
+ if (!mod) return Promise.resolve({ ok: false, error: "nfc_unavailable" });
490
+ return mod.readOnce(timeoutMs);
491
+ }
492
+ };
493
+ }
494
+ function createBluetoothAPI() {
495
+ const refuse = (method) => new CapabilityUnavailableError(
496
+ `bluetooth.${method}`,
497
+ "Bluetooth is not implemented in this build \u2014 no BLE native module is installed. The capability is declared so it fails by name rather than silently; nothing was scanned."
498
+ );
499
+ return {
500
+ // These two answer `false` rather than throwing, because "is BLE usable?"
501
+ // is exactly the question a plugin should be allowed to ask before
502
+ // committing to a flow, and `false` is the true answer here.
503
+ async isSupported() {
504
+ return false;
505
+ },
506
+ async isEnabled() {
507
+ return false;
508
+ },
509
+ // scan() THROWS, because there is no honest empty result: an empty device
510
+ // list is a real finding ("nothing is advertising nearby") and returning
511
+ // one would report a scan that never happened.
512
+ async scan() {
513
+ throw refuse("scan");
514
+ }
515
+ };
516
+ }
517
+ function createVisionAPI() {
518
+ return {
519
+ // "Can I see?" — true once the native module is present in the binary. On a
520
+ // build without it, adaVision.isSupported() answers false, and assessQuality
521
+ // below refuses cleanly (no crash), exactly the pre-module behaviour.
522
+ async isSupported() {
523
+ return isSupported();
524
+ },
525
+ // readText: on-device OCR on a published frame (native resolves the id →
526
+ // pixels). [] = looked, found no text (a real finding); throws = could not
527
+ // look (unknown/aged-out id). describe (VNClassifyImage) is the next pass.
528
+ async readText(frameId, opts) {
529
+ const langs = opts?.languages;
530
+ if (langs != null && (!Array.isArray(langs) || langs.some((l) => typeof l !== "string"))) {
531
+ throw refuseArgument("vision", "readText", `languages must be an array of language codes, not ${shown(langs)}`, "nothing was read");
532
+ }
533
+ return readText(frameId, langs);
534
+ },
535
+ // describe: on-device labels (VNClassifyImage), not prose — the sentence is
536
+ // the skill's job. [] = looked, recognised nothing.
537
+ async describe(frameId, opts) {
538
+ return describe(frameId, countArg("vision", "describe", "maxLabels", opts?.maxLabels, 5, 50, "nothing was labelled"));
539
+ },
540
+ // detectObjects: on-device located objects (bundled detector), each with a
541
+ // box — what a guidance loop reads to say WHERE a thing is, not just that the
542
+ // scene contains it. [] = looked, found nothing; throws = could not look.
543
+ async detectObjects(frameId, opts) {
544
+ const nothing = "nothing was detected";
545
+ return detectObjects(
546
+ frameId,
547
+ countArg("vision", "detectObjects", "maxItems", opts?.maxItems, 10, 50, nothing),
548
+ fractionArg("vision", "detectObjects", "minConfidence", opts?.minConfidence, 0.25, nothing)
549
+ );
550
+ },
551
+ // assessQuality: resolve the frame id to its LOCAL file, measure on-device,
552
+ // and record the result back onto the frame so a later read of
553
+ // VisualFrameRef.quality reflects it. Throwing here means "could not look"
554
+ // (unknown/aged-out id, or no native module) — never a measured verdict.
555
+ async assessQuality(frameId) {
556
+ const q = qualityById(frameId);
557
+ if (!q) {
558
+ throw new CapabilityUnavailableError(
559
+ "vision.assessQuality",
560
+ `No frame for id "${frameId}" \u2014 unknown or aged out of the ring. This is "could not look", not a measurement.`
561
+ );
562
+ }
563
+ return q;
564
+ }
565
+ };
566
+ }
567
+ function createMapsAPI() {
568
+ const refuseIfMissing = (verb, nothing) => {
569
+ const missing = missingReason();
570
+ if (missing) {
571
+ throw new CapabilityUnavailableError(`maps.${verb}`, `maps.${verb} needs ${missing}; ${nothing}.`);
572
+ }
573
+ };
574
+ return {
575
+ async isSupported() {
576
+ return isSupported2();
577
+ },
578
+ // [] = Apple looked and found nothing (a real finding); throws = could not
579
+ // look. The defaults (radiusM 3000, limit 8) live in searchArgs.
580
+ async search(query, opts) {
581
+ const args = searchArgs(query, opts);
582
+ refuseIfMissing("search", "nothing was searched");
583
+ const raw = await search(args.query, args.near, args.radiusM, args.limit).catch((err) => {
584
+ throw mapsFailure("search", err);
585
+ });
586
+ return toMapsPlaces(raw, args.near);
587
+ },
588
+ // null = nothing at that point; throws = could not look.
589
+ async reverseGeocode(at) {
590
+ const point = coordinateArg("reverseGeocode", "at", at, "nothing was looked up");
591
+ const address = await reverseGeocode(point).catch((err) => {
592
+ throw mapsFailure("reverseGeocode", err);
593
+ });
594
+ return address ? toReverseGeocodedPlace(point, address) : null;
595
+ },
596
+ // null = Apple found no route. Never an empty 0 m route, which would read as
597
+ // "you have arrived". A remote bundle can pass any string as `mode`, so a
598
+ // mode this build cannot honour refuses rather than silently walking.
599
+ async route(from, to, opts) {
600
+ if (opts?.mode !== void 0 && opts.mode !== "walking") {
601
+ throw new CapabilityUnavailableError(
602
+ "maps.route",
603
+ `maps.route supports walking only, not "${String(opts.mode)}"; no route was requested.`
604
+ );
605
+ }
606
+ const a = coordinateArg("route", "from", from, "no route was requested");
607
+ const b = coordinateArg("route", "to", to, "no route was requested");
608
+ refuseIfMissing("route", "no route was requested");
609
+ const raw = await route(a, b).catch((err) => {
610
+ throw mapsFailure("route", err);
611
+ });
612
+ return raw ? toMapsRoute(raw) : null;
613
+ }
614
+ };
615
+ }
616
+ function createDeviceProvider(config) {
617
+ const connectivity = createConnectivityAPI(config?.reachabilityUrl);
618
+ return {
619
+ camera: createCameraAPI(),
620
+ location: createLocationAPI(),
621
+ // Only the per-plugin storageFor/fileSystemFor are exposed — NO shared
622
+ // `storage`/`fileSystem` bucket. The gate scopes by pluginId and fails
623
+ // closed without one, so a shared instance would be an unreachable
624
+ // (and dangerous) fallback. Each plugin gets its own namespace + db file /
625
+ // sandbox directory, or nothing.
626
+ storageFor: (pluginId) => createStorageAPI(pluginId),
627
+ biometrics: stubApi("biometrics"),
628
+ biometricsV2: createBiometricsAPIv2(),
629
+ notifications: createNotificationsAPI(),
630
+ haptics: createHapticsAPI(),
631
+ connectivity,
632
+ fileSystemFor: (pluginId) => createFileSystemAPI(pluginId),
633
+ cookies: createCookiesAPI(),
634
+ sharing: createSharingAPI(),
635
+ scanner: createScannerAPI(),
636
+ nfc: createNfcAPI(),
637
+ bluetooth: createBluetoothAPI(),
638
+ vision: createVisionAPI(),
639
+ maps: createMapsAPI()
640
+ };
641
+ }
642
+
643
+ export {
644
+ clearAllPluginData,
645
+ createDeviceProvider
646
+ };
647
+ //# sourceMappingURL=chunk-GF2MPTAB.mjs.map