@ateam-ai-mobile/expo 0.1.4 → 0.1.7

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 (158) 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 +2473 -0
  8. package/dist/bootstrap.js.map +1 -0
  9. package/dist/bootstrap.mjs +64 -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-4XYXJYN5.mjs +1513 -0
  14. package/dist/chunk-4XYXJYN5.mjs.map +1 -0
  15. package/dist/chunk-5HM6UA2K.mjs +571 -0
  16. package/dist/chunk-5HM6UA2K.mjs.map +1 -0
  17. package/dist/chunk-6LXF3JVX.mjs +96 -0
  18. package/dist/chunk-6LXF3JVX.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-KOXF2FZM.mjs +92 -0
  22. package/dist/chunk-KOXF2FZM.mjs.map +1 -0
  23. package/dist/chunk-L4V7OCJ3.mjs +71 -0
  24. package/dist/chunk-L4V7OCJ3.mjs.map +1 -0
  25. package/dist/chunk-TZXWVYYR.mjs +67 -0
  26. package/dist/chunk-TZXWVYYR.mjs.map +1 -0
  27. package/dist/chunk-VQJPSLHP.mjs +1801 -0
  28. package/dist/chunk-VQJPSLHP.mjs.map +1 -0
  29. package/dist/chunk-WMJKH4XE.mjs +34 -0
  30. package/dist/chunk-WMJKH4XE.mjs.map +1 -0
  31. package/dist/chunk-XQSY6MHP.mjs +213 -0
  32. package/dist/chunk-XQSY6MHP.mjs.map +1 -0
  33. package/dist/createBridge.mjs +2 -0
  34. package/dist/createBridge.mjs.map +1 -1
  35. package/dist/device/createDeviceProvider.d.mts +23 -0
  36. package/dist/device/createDeviceProvider.d.ts +23 -0
  37. package/dist/device/createDeviceProvider.js +967 -0
  38. package/dist/device/createDeviceProvider.js.map +1 -0
  39. package/dist/device/createDeviceProvider.mjs +17 -0
  40. package/dist/device/createDeviceProvider.mjs.map +1 -0
  41. package/dist/device-bridge/collectors/appEngagement.d.mts +10 -0
  42. package/dist/device-bridge/collectors/appEngagement.d.ts +10 -0
  43. package/dist/device-bridge/collectors/appEngagement.js +128 -0
  44. package/dist/device-bridge/collectors/appEngagement.js.map +1 -0
  45. package/dist/device-bridge/collectors/appEngagement.mjs +12 -0
  46. package/dist/device-bridge/collectors/appEngagement.mjs.map +1 -0
  47. package/dist/device-bridge/collectors/health.d.mts +24 -0
  48. package/dist/device-bridge/collectors/health.d.ts +24 -0
  49. package/dist/device-bridge/collectors/health.js +238 -0
  50. package/dist/device-bridge/collectors/health.js.map +1 -0
  51. package/dist/device-bridge/collectors/health.mjs +18 -0
  52. package/dist/device-bridge/collectors/health.mjs.map +1 -0
  53. package/dist/device-bridge/cookies.d.mts +49 -0
  54. package/dist/device-bridge/cookies.d.ts +49 -0
  55. package/dist/device-bridge/cookies.js +90 -0
  56. package/dist/device-bridge/cookies.js.map +1 -0
  57. package/dist/device-bridge/cookies.mjs +14 -0
  58. package/dist/device-bridge/cookies.mjs.map +1 -0
  59. package/dist/device-bridge/index.d.mts +483 -0
  60. package/dist/device-bridge/index.d.ts +483 -0
  61. package/dist/device-bridge/index.js +2084 -0
  62. package/dist/device-bridge/index.js.map +1 -0
  63. package/dist/device-bridge/index.mjs +32 -0
  64. package/dist/device-bridge/index.mjs.map +1 -0
  65. package/dist/device-bridge/nfc.d.mts +30 -0
  66. package/dist/device-bridge/nfc.d.ts +30 -0
  67. package/dist/device-bridge/nfc.js +109 -0
  68. package/dist/device-bridge/nfc.js.map +1 -0
  69. package/dist/device-bridge/nfc.mjs +14 -0
  70. package/dist/device-bridge/nfc.mjs.map +1 -0
  71. package/dist/index.d.mts +493 -18
  72. package/dist/index.d.ts +493 -18
  73. package/dist/index.js +1409 -6
  74. package/dist/index.js.map +1 -1
  75. package/dist/index.mjs +23 -194
  76. package/dist/index.mjs.map +1 -1
  77. package/dist/oauth/expoOAuth.d.mts +18 -0
  78. package/dist/oauth/expoOAuth.d.ts +18 -0
  79. package/dist/oauth/expoOAuth.js +102 -0
  80. package/dist/oauth/expoOAuth.js.map +1 -0
  81. package/dist/oauth/expoOAuth.mjs +8 -0
  82. package/dist/oauth/expoOAuth.mjs.map +1 -0
  83. package/dist/types-BRanJYTn.d.mts +138 -0
  84. package/dist/types-BRanJYTn.d.ts +138 -0
  85. package/dist/vision/index.d.mts +81 -0
  86. package/dist/vision/index.d.ts +81 -0
  87. package/dist/vision/index.js +101 -0
  88. package/dist/vision/index.js.map +1 -0
  89. package/dist/vision/index.mjs +28 -0
  90. package/dist/vision/index.mjs.map +1 -0
  91. package/expo-module.config.json +9 -0
  92. package/ios/AdaVision.podspec +28 -0
  93. package/ios/AdaVisionModule.swift +432 -0
  94. package/ios/Resources/yolov8n-oiv7.mlmodelc/analytics/coremldata.bin +0 -0
  95. package/ios/Resources/yolov8n-oiv7.mlmodelc/coremldata.bin +0 -0
  96. package/ios/Resources/yolov8n-oiv7.mlmodelc/metadata.json +773 -0
  97. package/ios/Resources/yolov8n-oiv7.mlmodelc/model0/analytics/coremldata.bin +0 -0
  98. package/ios/Resources/yolov8n-oiv7.mlmodelc/model0/coremldata.bin +0 -0
  99. package/ios/Resources/yolov8n-oiv7.mlmodelc/model0/model.mil +720 -0
  100. package/ios/Resources/yolov8n-oiv7.mlmodelc/model0/weights/weight.bin +0 -0
  101. package/ios/Resources/yolov8n-oiv7.mlmodelc/model1/coremldata.bin +0 -0
  102. package/package.json +107 -7
  103. package/src/bootstrap.ts +159 -0
  104. package/src/camera/CameraTaskHost.tsx +175 -0
  105. package/src/camera/cameraTasks.ts +129 -0
  106. package/src/device/createDeviceProvider.ts +832 -0
  107. package/src/device-bridge/actions/calendar-actions.ts +217 -0
  108. package/src/device-bridge/actions/dnd.ts +74 -0
  109. package/src/device-bridge/actions/health-actions.ts +58 -0
  110. package/src/device-bridge/actions/index.ts +12 -0
  111. package/src/device-bridge/actions/messaging.ts +74 -0
  112. package/src/device-bridge/actions/navigation.ts +88 -0
  113. package/src/device-bridge/actions/queue-poller.ts +151 -0
  114. package/src/device-bridge/background.ts +137 -0
  115. package/src/device-bridge/biometrics.ts +64 -0
  116. package/src/device-bridge/capabilities.ts +218 -0
  117. package/src/device-bridge/collectors/appEngagement.ts +120 -0
  118. package/src/device-bridge/collectors/battery.ts +83 -0
  119. package/src/device-bridge/collectors/calendar.ts +162 -0
  120. package/src/device-bridge/collectors/camera.ts +27 -0
  121. package/src/device-bridge/collectors/connectivity.ts +60 -0
  122. package/src/device-bridge/collectors/contacts.ts +200 -0
  123. package/src/device-bridge/collectors/health.ts +299 -0
  124. package/src/device-bridge/collectors/index.ts +12 -0
  125. package/src/device-bridge/collectors/location.ts +224 -0
  126. package/src/device-bridge/collectors/mood.ts +141 -0
  127. package/src/device-bridge/collectors/notifications.ts +70 -0
  128. package/src/device-bridge/cookies.ts +89 -0
  129. package/src/device-bridge/dynamic-connector.ts +422 -0
  130. package/src/device-bridge/index.ts +467 -0
  131. package/src/device-bridge/nfc.ts +85 -0
  132. package/src/device-bridge/plugin.ts +71 -0
  133. package/src/device-bridge/relay-client.ts +237 -0
  134. package/src/device-bridge/scanner.ts +42 -0
  135. package/src/device-bridge/sharing.ts +35 -0
  136. package/src/device-bridge/types.ts +326 -0
  137. package/src/device-state/activityClassifier.ts +151 -0
  138. package/src/device-state/activityEngine.ts +252 -0
  139. package/src/device-state/collectors.ts +31 -0
  140. package/src/device-state/domains/activity.ts +93 -0
  141. package/src/device-state/domains/capability.ts +60 -0
  142. package/src/device-state/domains/connectivity.ts +60 -0
  143. package/src/device-state/domains/deviceContext.ts +55 -0
  144. package/src/device-state/domains/interaction.ts +59 -0
  145. package/src/device-state/domains/spatial.ts +283 -0
  146. package/src/device-state/domains/visual.ts +100 -0
  147. package/src/device-state/headingSource.ts +84 -0
  148. package/src/device-state/index.ts +77 -0
  149. package/src/device-state/quality.ts +60 -0
  150. package/src/device-state/replay.ts +220 -0
  151. package/src/device-state/turnDetector.ts +121 -0
  152. package/src/device-state/visualEngine.ts +341 -0
  153. package/src/haptics.ts +4 -0
  154. package/src/index.ts +37 -0
  155. package/src/oauth/expoOAuth.tsx +113 -0
  156. package/src/vision/analysis.js +80 -0
  157. package/src/vision/index.ts +144 -0
  158. package/src/vision/ring.js +35 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/haptics.ts","../src/bundleStorage.ts","../src/attachmentCache.ts"],"sourcesContent":["/**\n * @ateam-ai-mobile/expo — Expo-backed providers for the ADAS SDK.\n *\n * Bare-RN hosts skip this package entirely (core + plugin-runtime have safe\n * defaults); Expo hosts call setupExpoProviders() once at startup to light\n * up haptics, persistent bundle caching, attachment previews, and the\n * expo modules remote bundles may require.\n */\nimport * as ExpoWebBrowser from 'expo-web-browser';\nimport * as ExpoLinking from 'expo-linking';\nimport * as ExpoClipboard from 'expo-clipboard';\nimport AsyncStorage from '@react-native-async-storage/async-storage';\nimport { setAcsCacheStorage } from '@ateam-ai-mobile/core';\nimport {\n setHapticsProvider,\n setBundleStorage,\n registerBundleModules,\n} from '@ateam-ai-mobile/plugin-runtime';\nimport { setClipboardProvider } from '@ateam-ai-mobile/ui';\n\nimport { expoHaptics } from './haptics';\nimport { ExpoBundleStorage } from './bundleStorage';\nimport { ExpoAttachmentCache } from './attachmentCache';\n\nexport { expoHaptics } from './haptics';\nexport { ExpoBundleStorage } from './bundleStorage';\nexport { ExpoAttachmentCache } from './attachmentCache';\n// NOTE: createBridge (device capabilities bridge) is intentionally NOT\n// exported here — it statically imports the optional expo modules\n// (calendar/contacts/location/…), which would break Metro builds in hosts\n// that don't install them. Install those modules and import it from the\n// subpath: `import { createBridge } from '@ateam-ai-mobile/expo/bridge'`.\n\n/**\n * Wire all Expo providers in one call. Runs before initAdas() is fine —\n * these registries are independent of the core config.\n *\n * Returns the attachment cache so the host can pass it to initAdas():\n * const { attachmentCache } = setupExpoProviders();\n * initAdas({ ..., attachmentCache });\n */\nexport function setupExpoProviders(opts?: {\n /** Extra modules remote bundles may require(), e.g. react-native-webview.\n * Static imports must live in the HOST (it owns the native build). */\n bundleModules?: Record<string, any>;\n /** AsyncStorage key overrides — pass your pre-SDK keys when migrating an\n * existing app so users keep their attachment previews / bundle cache. */\n attachmentIndexKey?: string;\n bundleIndexKey?: string;\n}): { attachmentCache: ExpoAttachmentCache } {\n setHapticsProvider(expoHaptics);\n setBundleStorage(new ExpoBundleStorage({ indexKey: opts?.bundleIndexKey }));\n setClipboardProvider({\n setString: (text: string) => ExpoClipboard.setStringAsync(text).then(() => {}),\n });\n registerBundleModules({\n 'expo-web-browser': ExpoWebBrowser,\n 'expo-linking': ExpoLinking,\n ...(opts?.bundleModules || {}),\n });\n // Persist the ACS home-actions feed across cold starts.\n setAcsCacheStorage({\n getItem: (k: string) => AsyncStorage.getItem(k),\n setItem: (k: string, v: string) => AsyncStorage.setItem(k, v),\n });\n return { attachmentCache: new ExpoAttachmentCache({ indexKey: opts?.attachmentIndexKey }) };\n}\n","/**\n * expo-haptics implementation of the plugin HapticsAPI.\n */\nimport * as Haptics from 'expo-haptics';\nimport type { HapticsAPI } from '@ateam-ai-mobile/plugin-runtime';\n\nexport const expoHaptics: HapticsAPI = {\n impact(style) {\n const map = {\n light: Haptics.ImpactFeedbackStyle.Light,\n medium: Haptics.ImpactFeedbackStyle.Medium,\n heavy: Haptics.ImpactFeedbackStyle.Heavy,\n } as const;\n Haptics.impactAsync(map[style]).catch(() => {});\n },\n notification(type) {\n const map = {\n success: Haptics.NotificationFeedbackType.Success,\n warning: Haptics.NotificationFeedbackType.Warning,\n error: Haptics.NotificationFeedbackType.Error,\n } as const;\n Haptics.notificationAsync(map[type]).catch(() => {});\n },\n selection() {\n Haptics.selectionAsync().catch(() => {});\n },\n};\n","/**\n * Disk-backed BundleStorage: bundle files in the Expo cache directory,\n * index in AsyncStorage. Mirrors the reference app's cache semantics\n * (index version key, files under plugin-bundles/).\n */\nimport * as FileSystem from 'expo-file-system/legacy';\nimport AsyncStorage from '@react-native-async-storage/async-storage';\nimport type { BundleStorage, BundleCacheEntry } from '@ateam-ai-mobile/plugin-runtime';\n\nconst CACHE_DIR = `${FileSystem.cacheDirectory}plugin-bundles/`;\nconst DEFAULT_CACHE_INDEX_KEY = 'adas-plugin-bundles-index-v1';\n\nexport class ExpoBundleStorage implements BundleStorage {\n private dirReady = false;\n private indexKey: string;\n\n /** Pass `indexKey` when migrating from an app that already persisted a\n * bundle index under a different key — keeps the existing cache warm. */\n constructor(opts?: { indexKey?: string }) {\n this.indexKey = opts?.indexKey || DEFAULT_CACHE_INDEX_KEY;\n }\n\n private async ensureDir(): Promise<void> {\n if (this.dirReady) return;\n try {\n const info = await FileSystem.getInfoAsync(CACHE_DIR);\n if (!info.exists) {\n await FileSystem.makeDirectoryAsync(CACHE_DIR, { intermediates: true });\n }\n } catch (err) {\n console.warn('[ExpoBundleStorage] cache dir error:', err);\n }\n this.dirReady = true;\n }\n\n async loadIndex(): Promise<Record<string, BundleCacheEntry>> {\n try {\n const raw = await AsyncStorage.getItem(this.indexKey);\n return raw ? JSON.parse(raw) : {};\n } catch {\n return {};\n }\n }\n\n async saveIndex(index: Record<string, BundleCacheEntry>): Promise<void> {\n try {\n await AsyncStorage.setItem(this.indexKey, JSON.stringify(index));\n } catch (err) {\n console.warn('[ExpoBundleStorage] index save error:', err);\n }\n }\n\n async readBundle(localPath: string): Promise<string | null> {\n try {\n const info = await FileSystem.getInfoAsync(localPath);\n if (!info.exists) return null;\n return await FileSystem.readAsStringAsync(localPath);\n } catch {\n return null; // file gone — caller re-downloads\n }\n }\n\n async writeBundle(key: string, content: string): Promise<string> {\n await this.ensureDir();\n const localPath = `${CACHE_DIR}${key}`;\n await FileSystem.writeAsStringAsync(localPath, content);\n return localPath;\n }\n\n async deleteBundle(localPath: string): Promise<void> {\n await FileSystem.deleteAsync(localPath, { idempotent: true }).catch(() => {});\n }\n\n async clearAll(): Promise<void> {\n await FileSystem.deleteAsync(CACHE_DIR, { idempotent: true }).catch(() => {});\n await AsyncStorage.removeItem(this.indexKey).catch(() => {});\n this.dirReady = false;\n }\n}\n","/**\n * Expo implementation of @ateam-ai-mobile/core's AttachmentCache: attachment bytes on\n * disk, index in AsyncStorage. Mirrors the reference app's chat attachment\n * cache (last-100 retention).\n */\nimport * as FileSystem from 'expo-file-system/legacy';\nimport AsyncStorage from '@react-native-async-storage/async-storage';\nimport type { AttachmentCache, AttachmentPreview, OutgoingAttachment } from '@ateam-ai-mobile/core';\n\nconst DEFAULT_INDEX_KEY = 'adas-chat-attachment-index-v1';\nconst DIR = `${FileSystem.documentDirectory}chat-attachments/`;\nconst MAX_JOBS = 100;\n\ninterface CachedAttachment { mimeType: string; name: string; filePath: string }\n\nexport class ExpoAttachmentCache implements AttachmentCache {\n private index: Record<string, CachedAttachment[]> = {};\n private loaded: Promise<void>;\n private indexKey: string;\n\n /** Pass `indexKey` when migrating from an app that already persisted an\n * index under a different AsyncStorage key — otherwise existing users\n * lose every cached preview on upgrade. */\n constructor(opts?: { indexKey?: string }) {\n const indexKey = opts?.indexKey || DEFAULT_INDEX_KEY;\n this.indexKey = indexKey;\n this.loaded = (async () => {\n try {\n const info = await FileSystem.getInfoAsync(DIR);\n if (!info.exists) await FileSystem.makeDirectoryAsync(DIR, { intermediates: true });\n const raw = await AsyncStorage.getItem(indexKey);\n if (raw) this.index = JSON.parse(raw);\n } catch {}\n })();\n }\n\n async ready(): Promise<void> {\n await this.loaded;\n }\n\n async save(jobId: string, attachments: OutgoingAttachment[]): Promise<void> {\n await this.loaded;\n const entries: CachedAttachment[] = [];\n for (let i = 0; i < attachments.length; i++) {\n const att = attachments[i];\n const ext = att.mimeType.startsWith('image/') ? att.mimeType.split('/')[1] || 'jpg' : 'bin';\n const filePath = `${DIR}${jobId}_${i}.${ext}`;\n try {\n await FileSystem.writeAsStringAsync(filePath, att.data, { encoding: FileSystem.EncodingType.Base64 });\n entries.push({ mimeType: att.mimeType, name: att.name, filePath });\n } catch (err) {\n console.warn('[ExpoAttachmentCache] write failed:', err);\n }\n }\n if (entries.length === 0) return;\n\n this.index[jobId] = entries;\n // Keep only the most recent MAX_JOBS jobs; delete evicted files.\n const keys = Object.keys(this.index);\n if (keys.length > MAX_JOBS) {\n for (const k of keys.slice(0, keys.length - MAX_JOBS)) {\n const old = this.index[k];\n if (old) for (const o of old) FileSystem.deleteAsync(o.filePath, { idempotent: true }).catch(() => {});\n delete this.index[k];\n }\n }\n try {\n await AsyncStorage.setItem(this.indexKey, JSON.stringify(this.index));\n } catch {}\n }\n\n get(jobId: string): AttachmentPreview[] | undefined {\n const entries = this.index[jobId];\n if (!entries || entries.length === 0) return undefined;\n return entries.map(e => ({\n mimeType: e.mimeType,\n name: e.name,\n previewUri: e.filePath,\n }));\n }\n}\n"],"mappings":"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","names":["AsyncStorage","FileSystem","AsyncStorage","AsyncStorage"]}
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,18 @@
1
+ import { OAuthProvider } from '@ateam-ai-mobile/ui';
2
+
3
+ interface ExpoOAuthConfig {
4
+ /**
5
+ * The host's bundled Google client ids, used by the join / open-join screens
6
+ * that carry no tenant config (they pass no cfg to signInWithGoogle). The
7
+ * login screen passes the tenant's configured ids and overrides these.
8
+ */
9
+ googleWebClientId?: string;
10
+ googleIosClientId?: string;
11
+ }
12
+ /**
13
+ * Build the native OAuth provider. Wire it once at startup:
14
+ * setOAuthProvider(createExpoOAuthProvider({ googleWebClientId, googleIosClientId }));
15
+ */
16
+ declare function createExpoOAuthProvider(host?: ExpoOAuthConfig): OAuthProvider;
17
+
18
+ export { type ExpoOAuthConfig, createExpoOAuthProvider };
@@ -0,0 +1,18 @@
1
+ import { OAuthProvider } from '@ateam-ai-mobile/ui';
2
+
3
+ interface ExpoOAuthConfig {
4
+ /**
5
+ * The host's bundled Google client ids, used by the join / open-join screens
6
+ * that carry no tenant config (they pass no cfg to signInWithGoogle). The
7
+ * login screen passes the tenant's configured ids and overrides these.
8
+ */
9
+ googleWebClientId?: string;
10
+ googleIosClientId?: string;
11
+ }
12
+ /**
13
+ * Build the native OAuth provider. Wire it once at startup:
14
+ * setOAuthProvider(createExpoOAuthProvider({ googleWebClientId, googleIosClientId }));
15
+ */
16
+ declare function createExpoOAuthProvider(host?: ExpoOAuthConfig): OAuthProvider;
17
+
18
+ export { type ExpoOAuthConfig, createExpoOAuthProvider };
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/oauth/expoOAuth.tsx
31
+ var expoOAuth_exports = {};
32
+ __export(expoOAuth_exports, {
33
+ createExpoOAuthProvider: () => createExpoOAuthProvider
34
+ });
35
+ module.exports = __toCommonJS(expoOAuth_exports);
36
+ var import_react_native = require("react-native");
37
+ var import_google_signin = require("@react-native-google-signin/google-signin");
38
+ var AppleAuthentication = __toESM(require("expo-apple-authentication"));
39
+ var import_jsx_runtime = require("react/jsx-runtime");
40
+ var NOOP = () => {
41
+ };
42
+ function createExpoOAuthProvider(host = {}) {
43
+ return {
44
+ async signInWithGoogle(cfg) {
45
+ const webClientId = cfg?.webClientId || host.googleWebClientId || "";
46
+ const iosClientId = cfg?.iosClientId || host.googleIosClientId || "";
47
+ const params = { webClientId };
48
+ if (iosClientId) params.iosClientId = iosClientId;
49
+ import_google_signin.GoogleSignin.configure(params);
50
+ try {
51
+ await import_google_signin.GoogleSignin.hasPlayServices({ showPlayServicesUpdateDialog: true });
52
+ const result = await import_google_signin.GoogleSignin.signIn();
53
+ return result?.data?.idToken || result?.idToken || null;
54
+ } catch (err) {
55
+ const code = err?.code;
56
+ if (code === import_google_signin.statusCodes.SIGN_IN_CANCELLED || code === import_google_signin.statusCodes.IN_PROGRESS) {
57
+ return null;
58
+ }
59
+ throw err;
60
+ }
61
+ },
62
+ async signInWithApple() {
63
+ try {
64
+ const credential = await AppleAuthentication.signInAsync({
65
+ requestedScopes: [
66
+ AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
67
+ AppleAuthentication.AppleAuthenticationScope.EMAIL
68
+ ]
69
+ });
70
+ return credential.identityToken || null;
71
+ } catch (err) {
72
+ if (err?.code === "ERR_REQUEST_CANCELED") return null;
73
+ throw err;
74
+ }
75
+ },
76
+ async isAppleAvailable() {
77
+ if (import_react_native.Platform.OS !== "ios") return false;
78
+ try {
79
+ return await AppleAuthentication.isAvailableAsync();
80
+ } catch {
81
+ return false;
82
+ }
83
+ },
84
+ renderAppleButton({ onPress, disabled, style }) {
85
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
86
+ AppleAuthentication.AppleAuthenticationButton,
87
+ {
88
+ buttonType: AppleAuthentication.AppleAuthenticationButtonType.CONTINUE,
89
+ buttonStyle: AppleAuthentication.AppleAuthenticationButtonStyle.BLACK,
90
+ cornerRadius: 999,
91
+ style,
92
+ onPress: disabled ? NOOP : onPress
93
+ }
94
+ );
95
+ }
96
+ };
97
+ }
98
+ // Annotate the CommonJS export names for ESM import in node:
99
+ 0 && (module.exports = {
100
+ createExpoOAuthProvider
101
+ });
102
+ //# sourceMappingURL=expoOAuth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/oauth/expoOAuth.tsx"],"sourcesContent":["/**\n * @ateam-ai-mobile/expo/oauth — the native OAuth provider for the relocated\n * auth screens (LoginScreen / JoinScreen / OpenJoinScreen in @ateam-ai-mobile/ui).\n *\n * This is the ONLY place @react-native-google-signin + expo-apple-authentication\n * are imported. The `ui` package stays native-free: its screens call\n * getOAuthProvider() for the id_token acquisition + the real Apple HIG button.\n *\n * Deliberately a SUBPATH (`@ateam-ai-mobile/expo/oauth`), not part of the main\n * entry — same rule as `/bridge` and `/device`: a host that doesn't install\n * these native modules must still be able to build @ateam-ai-mobile/expo.\n *\n * Behaviour is ported verbatim from the app's old login.tsx so the iPhone\n * parity gate sees no change:\n * - Google: configure({ webClientId, iosClientId }) → hasPlayServices →\n * signIn → normalize the v15-vs-older id_token shape. A missing iosClientId\n * silently falls back to a web flow (unchanged); the caller gates on\n * webClientId, so we never reach here without one for the login path.\n * - a user-cancel (SIGN_IN_CANCELLED / IN_PROGRESS / ERR_REQUEST_CANCELED)\n * resolves to null — the screen treats null as \"no error\", never a red flash.\n */\nimport React from 'react';\nimport { Platform } from 'react-native';\nimport {\n GoogleSignin,\n statusCodes,\n type ConfigureParams,\n} from '@react-native-google-signin/google-signin';\nimport * as AppleAuthentication from 'expo-apple-authentication';\nimport type { OAuthProvider, OAuthGoogleConfig } from '@ateam-ai-mobile/ui';\n\nconst NOOP = () => {};\n\nexport interface ExpoOAuthConfig {\n /**\n * The host's bundled Google client ids, used by the join / open-join screens\n * that carry no tenant config (they pass no cfg to signInWithGoogle). The\n * login screen passes the tenant's configured ids and overrides these.\n */\n googleWebClientId?: string;\n googleIosClientId?: string;\n}\n\n/**\n * Build the native OAuth provider. Wire it once at startup:\n * setOAuthProvider(createExpoOAuthProvider({ googleWebClientId, googleIosClientId }));\n */\nexport function createExpoOAuthProvider(host: ExpoOAuthConfig = {}): OAuthProvider {\n return {\n async signInWithGoogle(cfg?: OAuthGoogleConfig): Promise<string | null> {\n const webClientId = cfg?.webClientId || host.googleWebClientId || '';\n const iosClientId = cfg?.iosClientId || host.googleIosClientId || '';\n // configure is idempotent + cheap; do it at sign-in time so the tenant's\n // ids are always current (replaces login.tsx's configure effect).\n const params: ConfigureParams = { webClientId };\n if (iosClientId) (params as any).iosClientId = iosClientId;\n GoogleSignin.configure(params);\n try {\n // android-only; no-op on iOS. Called defensively, as before.\n await GoogleSignin.hasPlayServices({ showPlayServicesUpdateDialog: true });\n const result: any = await GoogleSignin.signIn();\n // v15+ returns { data: { idToken } }; older returns { idToken }.\n return result?.data?.idToken || result?.idToken || null;\n } catch (err: any) {\n const code = err?.code;\n if (code === statusCodes.SIGN_IN_CANCELLED || code === statusCodes.IN_PROGRESS) {\n return null;\n }\n throw err;\n }\n },\n\n async signInWithApple(): Promise<string | null> {\n try {\n const credential = await AppleAuthentication.signInAsync({\n requestedScopes: [\n AppleAuthentication.AppleAuthenticationScope.FULL_NAME,\n AppleAuthentication.AppleAuthenticationScope.EMAIL,\n ],\n });\n return credential.identityToken || null;\n } catch (err: any) {\n // ERR_REQUEST_CANCELED = the user dismissed the sheet.\n if (err?.code === 'ERR_REQUEST_CANCELED') return null;\n throw err;\n }\n },\n\n async isAppleAvailable(): Promise<boolean> {\n if (Platform.OS !== 'ios') return false;\n try {\n return await AppleAuthentication.isAvailableAsync();\n } catch {\n return false;\n }\n },\n\n renderAppleButton({ onPress, disabled, style }): React.ReactNode {\n // Apple's HIG requires their own styled button when Apple Sign-In sits\n // alongside other providers. Same chrome the app shipped: CONTINUE /\n // BLACK / fully-rounded. Layout (width/height) comes from the screen.\n return (\n <AppleAuthentication.AppleAuthenticationButton\n buttonType={AppleAuthentication.AppleAuthenticationButtonType.CONTINUE}\n buttonStyle={AppleAuthentication.AppleAuthenticationButtonStyle.BLACK}\n cornerRadius={999}\n style={style as any}\n onPress={disabled ? NOOP : onPress}\n />\n );\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBA,0BAAyB;AACzB,2BAIO;AACP,0BAAqC;AA0E7B;AAvER,IAAM,OAAO,MAAM;AAAC;AAgBb,SAAS,wBAAwB,OAAwB,CAAC,GAAkB;AACjF,SAAO;AAAA,IACL,MAAM,iBAAiB,KAAiD;AACtE,YAAM,cAAc,KAAK,eAAe,KAAK,qBAAqB;AAClE,YAAM,cAAc,KAAK,eAAe,KAAK,qBAAqB;AAGlE,YAAM,SAA0B,EAAE,YAAY;AAC9C,UAAI,YAAa,CAAC,OAAe,cAAc;AAC/C,wCAAa,UAAU,MAAM;AAC7B,UAAI;AAEF,cAAM,kCAAa,gBAAgB,EAAE,8BAA8B,KAAK,CAAC;AACzE,cAAM,SAAc,MAAM,kCAAa,OAAO;AAE9C,eAAO,QAAQ,MAAM,WAAW,QAAQ,WAAW;AAAA,MACrD,SAAS,KAAU;AACjB,cAAM,OAAO,KAAK;AAClB,YAAI,SAAS,iCAAY,qBAAqB,SAAS,iCAAY,aAAa;AAC9E,iBAAO;AAAA,QACT;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IAEA,MAAM,kBAA0C;AAC9C,UAAI;AACF,cAAM,aAAa,MAA0B,gCAAY;AAAA,UACvD,iBAAiB;AAAA,YACK,6CAAyB;AAAA,YACzB,6CAAyB;AAAA,UAC/C;AAAA,QACF,CAAC;AACD,eAAO,WAAW,iBAAiB;AAAA,MACrC,SAAS,KAAU;AAEjB,YAAI,KAAK,SAAS,uBAAwB,QAAO;AACjD,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IAEA,MAAM,mBAAqC;AACzC,UAAI,6BAAS,OAAO,MAAO,QAAO;AAClC,UAAI;AACF,eAAO,MAA0B,qCAAiB;AAAA,MACpD,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,kBAAkB,EAAE,SAAS,UAAU,MAAM,GAAoB;AAI/D,aACE;AAAA,QAAqB;AAAA,QAApB;AAAA,UACC,YAAgC,kDAA8B;AAAA,UAC9D,aAAiC,mDAA+B;AAAA,UAChE,cAAc;AAAA,UACd;AAAA,UACA,SAAS,WAAW,OAAO;AAAA;AAAA,MAC7B;AAAA,IAEJ;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,8 @@
1
+ import {
2
+ createExpoOAuthProvider
3
+ } from "../chunk-L4V7OCJ3.mjs";
4
+ import "../chunk-WMJKH4XE.mjs";
5
+ export {
6
+ createExpoOAuthProvider
7
+ };
8
+ //# sourceMappingURL=expoOAuth.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,138 @@
1
+ interface DeviceBridgeConfig {
2
+ /** Cloud relay base URL (e.g., https://relay.example.com) */
3
+ relayUrl: string;
4
+ /** Unique device identifier */
5
+ deviceId: string;
6
+ /** Tenant ID — required by relay for data isolation */
7
+ tenant: string;
8
+ /** Actor/user ID — scopes device data per user in relay */
9
+ actorId?: string;
10
+ /** API key for relay authentication (reserved for future use) */
11
+ apiKey?: string;
12
+ /** Sync intervals per domain in milliseconds */
13
+ syncIntervals?: Partial<Record<string, number>>;
14
+ /** Enable background sync (requires expo-task-manager) */
15
+ backgroundSync?: boolean;
16
+ /** Callback for sync status changes */
17
+ onStatusChange?: (status: BridgeStatus) => void;
18
+ /** Callback for errors */
19
+ onError?: (error: BridgeError) => void;
20
+ }
21
+ type PermissionState = 'not_requested' | 'granted' | 'denied' | 'not_needed';
22
+ interface Capability {
23
+ /** Unique ID (e.g., 'calendar', 'contacts', 'whatsapp') */
24
+ id: string;
25
+ /** Human-readable name for UI */
26
+ name: string;
27
+ /** One-line description of what this capability does */
28
+ description: string;
29
+ /** Why the app needs this — shown to user BEFORE the OS dialog */
30
+ reason: string;
31
+ /** Does this capability require OS permission? */
32
+ requiresPermission: boolean;
33
+ /** Current permission state */
34
+ permissionState: PermissionState;
35
+ /** Request permission from the OS. Returns true if granted. */
36
+ requestPermission: () => Promise<boolean>;
37
+ /** Check current permission without prompting. */
38
+ checkPermission: () => Promise<boolean>;
39
+ /** Collect data for this capability. Returns domain data. */
40
+ collect: () => Promise<unknown>;
41
+ /** Default sync interval in ms */
42
+ defaultInterval: number;
43
+ /** Optional icon name (for host app UI) */
44
+ icon?: string;
45
+ /**
46
+ * Optional OS-event subscription. When provided, the bridge wires this up
47
+ * during startSync and the callback triggers an immediate sync of this
48
+ * capability — useful for sources that change unpredictably (battery
49
+ * level/state) where polling on a fixed interval misses changes while the
50
+ * app is backgrounded. Return an unsubscribe function.
51
+ */
52
+ subscribe?: (notify: () => void) => () => void;
53
+ }
54
+ type SyncState = 'idle' | 'syncing' | 'error' | 'stopped';
55
+ interface DomainSyncStatus {
56
+ domain: string;
57
+ lastSync: string | null;
58
+ state: SyncState;
59
+ error?: string;
60
+ itemCount?: number;
61
+ }
62
+ interface BridgeStatus {
63
+ running: boolean;
64
+ capabilities: CapabilityStatus[];
65
+ lastFullSync: string | null;
66
+ pendingActions: number;
67
+ }
68
+ interface CapabilityStatus {
69
+ id: string;
70
+ name: string;
71
+ permission: PermissionState;
72
+ sync: DomainSyncStatus;
73
+ }
74
+ interface BridgeError {
75
+ domain: string;
76
+ message: string;
77
+ code: string;
78
+ timestamp: string;
79
+ }
80
+ interface LocationData {
81
+ ok: true;
82
+ timestamp: string;
83
+ location: {
84
+ place: string;
85
+ address: string;
86
+ lat: number;
87
+ lng: number;
88
+ type: string;
89
+ };
90
+ }
91
+ interface HealthDayMetrics {
92
+ /** ISO date in local time, e.g. "2026-05-03" */
93
+ date: string;
94
+ /**
95
+ * False when HealthKit is unavailable or the user denied access.
96
+ *
97
+ * The metrics below are then null, NOT zero. A zero here used to be
98
+ * indistinguishable from a real sedentary day, so a denied permission was
99
+ * reported to the user as "you have taken 0 steps today" — and a coaching
100
+ * skill would act on it.
101
+ */
102
+ available: boolean;
103
+ /** Total step count for the day. null when unavailable. */
104
+ steps: number | null;
105
+ /** Flights of stairs climbed. null when unavailable. */
106
+ floors: number | null;
107
+ /** Active energy burned, kcal. null when unavailable. */
108
+ active_energy_kcal: number | null;
109
+ /** Walking + running distance, kilometers. null when unavailable. */
110
+ distance_km: number | null;
111
+ }
112
+ interface DeviceDataBundle {
113
+ deviceId: string;
114
+ timestamp: string;
115
+ domains: Record<string, unknown>;
116
+ }
117
+ type ActionType = 'messaging.send' | 'calendar.create' | 'calendar.reschedule' | 'calendar.cancel' | 'dnd.set' | 'navigation.start' | 'health.today' | 'health.history';
118
+ interface PendingAction {
119
+ id: string;
120
+ type: ActionType;
121
+ params: Record<string, unknown>;
122
+ created_at: string;
123
+ status: 'pending' | 'executing' | 'completed' | 'failed';
124
+ }
125
+ interface ActionResult {
126
+ id: string;
127
+ ok: boolean;
128
+ result?: Record<string, unknown>;
129
+ error?: string;
130
+ executed_at: string;
131
+ }
132
+ interface RelayResponse<T> {
133
+ ok: boolean;
134
+ data?: T;
135
+ error?: string;
136
+ }
137
+
138
+ export type { ActionResult as A, BridgeStatus as B, Capability as C, DeviceDataBundle as D, HealthDayMetrics as H, LocationData as L, PendingAction as P, RelayResponse as R, DeviceBridgeConfig as a, CapabilityStatus as b, PermissionState as c, BridgeError as d, DomainSyncStatus as e };
@@ -0,0 +1,138 @@
1
+ interface DeviceBridgeConfig {
2
+ /** Cloud relay base URL (e.g., https://relay.example.com) */
3
+ relayUrl: string;
4
+ /** Unique device identifier */
5
+ deviceId: string;
6
+ /** Tenant ID — required by relay for data isolation */
7
+ tenant: string;
8
+ /** Actor/user ID — scopes device data per user in relay */
9
+ actorId?: string;
10
+ /** API key for relay authentication (reserved for future use) */
11
+ apiKey?: string;
12
+ /** Sync intervals per domain in milliseconds */
13
+ syncIntervals?: Partial<Record<string, number>>;
14
+ /** Enable background sync (requires expo-task-manager) */
15
+ backgroundSync?: boolean;
16
+ /** Callback for sync status changes */
17
+ onStatusChange?: (status: BridgeStatus) => void;
18
+ /** Callback for errors */
19
+ onError?: (error: BridgeError) => void;
20
+ }
21
+ type PermissionState = 'not_requested' | 'granted' | 'denied' | 'not_needed';
22
+ interface Capability {
23
+ /** Unique ID (e.g., 'calendar', 'contacts', 'whatsapp') */
24
+ id: string;
25
+ /** Human-readable name for UI */
26
+ name: string;
27
+ /** One-line description of what this capability does */
28
+ description: string;
29
+ /** Why the app needs this — shown to user BEFORE the OS dialog */
30
+ reason: string;
31
+ /** Does this capability require OS permission? */
32
+ requiresPermission: boolean;
33
+ /** Current permission state */
34
+ permissionState: PermissionState;
35
+ /** Request permission from the OS. Returns true if granted. */
36
+ requestPermission: () => Promise<boolean>;
37
+ /** Check current permission without prompting. */
38
+ checkPermission: () => Promise<boolean>;
39
+ /** Collect data for this capability. Returns domain data. */
40
+ collect: () => Promise<unknown>;
41
+ /** Default sync interval in ms */
42
+ defaultInterval: number;
43
+ /** Optional icon name (for host app UI) */
44
+ icon?: string;
45
+ /**
46
+ * Optional OS-event subscription. When provided, the bridge wires this up
47
+ * during startSync and the callback triggers an immediate sync of this
48
+ * capability — useful for sources that change unpredictably (battery
49
+ * level/state) where polling on a fixed interval misses changes while the
50
+ * app is backgrounded. Return an unsubscribe function.
51
+ */
52
+ subscribe?: (notify: () => void) => () => void;
53
+ }
54
+ type SyncState = 'idle' | 'syncing' | 'error' | 'stopped';
55
+ interface DomainSyncStatus {
56
+ domain: string;
57
+ lastSync: string | null;
58
+ state: SyncState;
59
+ error?: string;
60
+ itemCount?: number;
61
+ }
62
+ interface BridgeStatus {
63
+ running: boolean;
64
+ capabilities: CapabilityStatus[];
65
+ lastFullSync: string | null;
66
+ pendingActions: number;
67
+ }
68
+ interface CapabilityStatus {
69
+ id: string;
70
+ name: string;
71
+ permission: PermissionState;
72
+ sync: DomainSyncStatus;
73
+ }
74
+ interface BridgeError {
75
+ domain: string;
76
+ message: string;
77
+ code: string;
78
+ timestamp: string;
79
+ }
80
+ interface LocationData {
81
+ ok: true;
82
+ timestamp: string;
83
+ location: {
84
+ place: string;
85
+ address: string;
86
+ lat: number;
87
+ lng: number;
88
+ type: string;
89
+ };
90
+ }
91
+ interface HealthDayMetrics {
92
+ /** ISO date in local time, e.g. "2026-05-03" */
93
+ date: string;
94
+ /**
95
+ * False when HealthKit is unavailable or the user denied access.
96
+ *
97
+ * The metrics below are then null, NOT zero. A zero here used to be
98
+ * indistinguishable from a real sedentary day, so a denied permission was
99
+ * reported to the user as "you have taken 0 steps today" — and a coaching
100
+ * skill would act on it.
101
+ */
102
+ available: boolean;
103
+ /** Total step count for the day. null when unavailable. */
104
+ steps: number | null;
105
+ /** Flights of stairs climbed. null when unavailable. */
106
+ floors: number | null;
107
+ /** Active energy burned, kcal. null when unavailable. */
108
+ active_energy_kcal: number | null;
109
+ /** Walking + running distance, kilometers. null when unavailable. */
110
+ distance_km: number | null;
111
+ }
112
+ interface DeviceDataBundle {
113
+ deviceId: string;
114
+ timestamp: string;
115
+ domains: Record<string, unknown>;
116
+ }
117
+ type ActionType = 'messaging.send' | 'calendar.create' | 'calendar.reschedule' | 'calendar.cancel' | 'dnd.set' | 'navigation.start' | 'health.today' | 'health.history';
118
+ interface PendingAction {
119
+ id: string;
120
+ type: ActionType;
121
+ params: Record<string, unknown>;
122
+ created_at: string;
123
+ status: 'pending' | 'executing' | 'completed' | 'failed';
124
+ }
125
+ interface ActionResult {
126
+ id: string;
127
+ ok: boolean;
128
+ result?: Record<string, unknown>;
129
+ error?: string;
130
+ executed_at: string;
131
+ }
132
+ interface RelayResponse<T> {
133
+ ok: boolean;
134
+ data?: T;
135
+ error?: string;
136
+ }
137
+
138
+ export type { ActionResult as A, BridgeStatus as B, Capability as C, DeviceDataBundle as D, HealthDayMetrics as H, LocationData as L, PendingAction as P, RelayResponse as R, DeviceBridgeConfig as a, CapabilityStatus as b, PermissionState as c, BridgeError as d, DomainSyncStatus as e };
@@ -0,0 +1,81 @@
1
+ import { ComponentType } from 'react';
2
+
3
+ /** TEST-ONLY live preview bound to the same headless session (so a tester can
4
+ * aim). The real Guide runs headless and never mounts this. Null on a binary
5
+ * without the native view, so importing this module never crashes. */
6
+ declare const CameraPreview: ComponentType<any> | null;
7
+ interface RawFrameQuality {
8
+ blur: 'sharp' | 'slight' | 'severe' | 'unknown';
9
+ exposure: 'good' | 'dark' | 'bright' | 'unknown';
10
+ /** true = lens covered; false = clearly not; null = not assessed. */
11
+ obstructed: boolean | null;
12
+ }
13
+ interface Subscription {
14
+ remove(): void;
15
+ }
16
+ /** A published timeline frame from the vision session (metadata only — never
17
+ * pixels; the buffer stays in the native ring, resolved by id). */
18
+ interface VisionFrame {
19
+ id: string;
20
+ ts: number;
21
+ expiresAt: number;
22
+ blur: RawFrameQuality['blur'];
23
+ exposure: RawFrameQuality['exposure'];
24
+ obstructed: RawFrameQuality['obstructed'];
25
+ }
26
+ /** One OCR result on a frame — matches the SDK's VisionText. */
27
+ interface VisionText {
28
+ text: string;
29
+ /** 0..1 recogniser confidence (never a 1.0 filler). */
30
+ confidence: number | null;
31
+ /** Normalised 0..1 box, origin TOP-left. */
32
+ box?: {
33
+ x: number;
34
+ y: number;
35
+ width: number;
36
+ height: number;
37
+ };
38
+ }
39
+ /** One classifier label — a vocabulary term, NOT prose. Matches VisionLabel. */
40
+ interface VisionLabel {
41
+ label: string;
42
+ confidence: number | null;
43
+ }
44
+ /** One detected object — a located item with a box, from the bundled detector. */
45
+ interface VisionObject {
46
+ /** Open-Images class name (e.g. "Car", "Traffic light", "Building", "Person"). */
47
+ label: string;
48
+ /** 0..1 detector confidence. */
49
+ confidence: number | null;
50
+ /** Normalised 0..1 box, origin TOP-left. */
51
+ box?: {
52
+ x: number;
53
+ y: number;
54
+ width: number;
55
+ height: number;
56
+ };
57
+ }
58
+ /** Is the native vision module present in this binary? */
59
+ declare function isSupported(): boolean;
60
+ /** One-shot: measure a frame's quality from its LOCAL file. Throws if it cannot look. */
61
+ declare function assessQuality(uri: string): Promise<RawFrameQuality>;
62
+ /** Start the vision session — publishes a timeline frame every `intervalMs`. */
63
+ declare function startVision(intervalMs?: number): Promise<void>;
64
+ /** Stop the vision session and release the camera. */
65
+ declare function stopVision(): void;
66
+ /** Subscribe to published timeline frames (id + quality + expiry; no pixels). */
67
+ declare function onVisionFrame(cb: (f: VisionFrame) => void): Subscription;
68
+ /** How far back the native ring can still resolve a frame id (ms). */
69
+ declare function visionRetentionMs(): number;
70
+ /** Resolve a published frame id → its measured quality (null if evicted). */
71
+ declare function qualityById(id: string): RawFrameQuality | null;
72
+ /** On-device OCR on a published frame. [] = looked, no text; throws = couldn't look. */
73
+ declare function readText(id: string, languages?: string[]): Promise<VisionText[]>;
74
+ /** On-device image classification → labels (not prose). [] = nothing recognised. */
75
+ declare function describe(id: string, maxLabels?: number): Promise<VisionLabel[]>;
76
+ /** On-device object detection (bundled YOLOv8n, Open-Images vocabulary) → located
77
+ * items with boxes. [] = looked, found nothing above `minConfidence`; throws =
78
+ * couldn't look (id aged out, or the model isn't in this build). */
79
+ declare function detectObjects(id: string, maxItems?: number, minConfidence?: number): Promise<VisionObject[]>;
80
+
81
+ export { CameraPreview, type RawFrameQuality, type VisionFrame, type VisionLabel, type VisionObject, type VisionText, assessQuality, describe, detectObjects, isSupported, onVisionFrame, qualityById, readText, startVision, stopVision, visionRetentionMs };
@@ -0,0 +1,81 @@
1
+ import { ComponentType } from 'react';
2
+
3
+ /** TEST-ONLY live preview bound to the same headless session (so a tester can
4
+ * aim). The real Guide runs headless and never mounts this. Null on a binary
5
+ * without the native view, so importing this module never crashes. */
6
+ declare const CameraPreview: ComponentType<any> | null;
7
+ interface RawFrameQuality {
8
+ blur: 'sharp' | 'slight' | 'severe' | 'unknown';
9
+ exposure: 'good' | 'dark' | 'bright' | 'unknown';
10
+ /** true = lens covered; false = clearly not; null = not assessed. */
11
+ obstructed: boolean | null;
12
+ }
13
+ interface Subscription {
14
+ remove(): void;
15
+ }
16
+ /** A published timeline frame from the vision session (metadata only — never
17
+ * pixels; the buffer stays in the native ring, resolved by id). */
18
+ interface VisionFrame {
19
+ id: string;
20
+ ts: number;
21
+ expiresAt: number;
22
+ blur: RawFrameQuality['blur'];
23
+ exposure: RawFrameQuality['exposure'];
24
+ obstructed: RawFrameQuality['obstructed'];
25
+ }
26
+ /** One OCR result on a frame — matches the SDK's VisionText. */
27
+ interface VisionText {
28
+ text: string;
29
+ /** 0..1 recogniser confidence (never a 1.0 filler). */
30
+ confidence: number | null;
31
+ /** Normalised 0..1 box, origin TOP-left. */
32
+ box?: {
33
+ x: number;
34
+ y: number;
35
+ width: number;
36
+ height: number;
37
+ };
38
+ }
39
+ /** One classifier label — a vocabulary term, NOT prose. Matches VisionLabel. */
40
+ interface VisionLabel {
41
+ label: string;
42
+ confidence: number | null;
43
+ }
44
+ /** One detected object — a located item with a box, from the bundled detector. */
45
+ interface VisionObject {
46
+ /** Open-Images class name (e.g. "Car", "Traffic light", "Building", "Person"). */
47
+ label: string;
48
+ /** 0..1 detector confidence. */
49
+ confidence: number | null;
50
+ /** Normalised 0..1 box, origin TOP-left. */
51
+ box?: {
52
+ x: number;
53
+ y: number;
54
+ width: number;
55
+ height: number;
56
+ };
57
+ }
58
+ /** Is the native vision module present in this binary? */
59
+ declare function isSupported(): boolean;
60
+ /** One-shot: measure a frame's quality from its LOCAL file. Throws if it cannot look. */
61
+ declare function assessQuality(uri: string): Promise<RawFrameQuality>;
62
+ /** Start the vision session — publishes a timeline frame every `intervalMs`. */
63
+ declare function startVision(intervalMs?: number): Promise<void>;
64
+ /** Stop the vision session and release the camera. */
65
+ declare function stopVision(): void;
66
+ /** Subscribe to published timeline frames (id + quality + expiry; no pixels). */
67
+ declare function onVisionFrame(cb: (f: VisionFrame) => void): Subscription;
68
+ /** How far back the native ring can still resolve a frame id (ms). */
69
+ declare function visionRetentionMs(): number;
70
+ /** Resolve a published frame id → its measured quality (null if evicted). */
71
+ declare function qualityById(id: string): RawFrameQuality | null;
72
+ /** On-device OCR on a published frame. [] = looked, no text; throws = couldn't look. */
73
+ declare function readText(id: string, languages?: string[]): Promise<VisionText[]>;
74
+ /** On-device image classification → labels (not prose). [] = nothing recognised. */
75
+ declare function describe(id: string, maxLabels?: number): Promise<VisionLabel[]>;
76
+ /** On-device object detection (bundled YOLOv8n, Open-Images vocabulary) → located
77
+ * items with boxes. [] = looked, found nothing above `minConfidence`; throws =
78
+ * couldn't look (id aged out, or the model isn't in this build). */
79
+ declare function detectObjects(id: string, maxItems?: number, minConfidence?: number): Promise<VisionObject[]>;
80
+
81
+ export { CameraPreview, type RawFrameQuality, type VisionFrame, type VisionLabel, type VisionObject, type VisionText, assessQuality, describe, detectObjects, isSupported, onVisionFrame, qualityById, readText, startVision, stopVision, visionRetentionMs };