@ateam-ai-mobile/expo 0.1.7 → 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 (71) hide show
  1. package/dist/bootstrap.js +841 -323
  2. package/dist/bootstrap.js.map +1 -1
  3. package/dist/bootstrap.mjs +9 -7
  4. package/dist/bootstrap.mjs.map +1 -1
  5. package/dist/chunk-7FWYEHN5.mjs +203 -0
  6. package/dist/chunk-7FWYEHN5.mjs.map +1 -0
  7. package/dist/{chunk-4XYXJYN5.mjs → chunk-C7M5WAHA.mjs} +583 -298
  8. package/dist/chunk-C7M5WAHA.mjs.map +1 -0
  9. package/dist/{chunk-5HM6UA2K.mjs → chunk-GF2MPTAB.mjs} +83 -7
  10. package/dist/chunk-GF2MPTAB.mjs.map +1 -0
  11. package/dist/chunk-J6XRNX7P.mjs +19 -0
  12. package/dist/chunk-J6XRNX7P.mjs.map +1 -0
  13. package/dist/{chunk-TZXWVYYR.mjs → chunk-PCAEUX2N.mjs} +1 -1
  14. package/dist/chunk-PCAEUX2N.mjs.map +1 -0
  15. package/dist/{chunk-VQJPSLHP.mjs → chunk-Z5AI2SXX.mjs} +13 -4
  16. package/dist/chunk-Z5AI2SXX.mjs.map +1 -0
  17. package/dist/createBridge.js +41 -10
  18. package/dist/createBridge.js.map +1 -1
  19. package/dist/createBridge.mjs +5 -1
  20. package/dist/createBridge.mjs.map +1 -1
  21. package/dist/device/createDeviceProvider.js +278 -17
  22. package/dist/device/createDeviceProvider.js.map +1 -1
  23. package/dist/device/createDeviceProvider.mjs +5 -3
  24. package/dist/device-bridge/index.d.mts +13 -1
  25. package/dist/device-bridge/index.d.ts +13 -1
  26. package/dist/device-bridge/index.js +49 -12
  27. package/dist/device-bridge/index.js.map +1 -1
  28. package/dist/device-bridge/index.mjs +3 -1
  29. package/dist/index.d.mts +19 -3
  30. package/dist/index.d.ts +19 -3
  31. package/dist/index.js +594 -297
  32. package/dist/index.js.map +1 -1
  33. package/dist/index.mjs +2 -1
  34. package/dist/maps/index.d.mts +56 -0
  35. package/dist/maps/index.d.ts +56 -0
  36. package/dist/maps/index.js +95 -0
  37. package/dist/maps/index.js.map +1 -0
  38. package/dist/maps/index.mjs +17 -0
  39. package/dist/maps/index.mjs.map +1 -0
  40. package/dist/vision/index.d.mts +4 -2
  41. package/dist/vision/index.d.ts +4 -2
  42. package/dist/vision/index.js.map +1 -1
  43. package/dist/vision/index.mjs +1 -1
  44. package/expo-module.config.json +1 -1
  45. package/ios/AdaMaps/AdaMapsModule.swift +180 -0
  46. package/ios/AdaMaps.podspec +25 -0
  47. package/ios/AdaVision.podspec +4 -0
  48. package/ios/AdaVisionModule.swift +63 -9
  49. package/package.json +10 -4
  50. package/src/args.ts +56 -0
  51. package/src/createBridge.ts +3 -1
  52. package/src/device/createDeviceProvider.ts +88 -3
  53. package/src/device-bridge/collectors/location.ts +21 -9
  54. package/src/device-state/collectors.ts +5 -1
  55. package/src/device-state/domains/deviceContext.ts +5 -3
  56. package/src/device-state/domains/interaction.ts +2 -1
  57. package/src/device-state/domains/spatial.ts +200 -116
  58. package/src/device-state/domains/visual.ts +34 -13
  59. package/src/device-state/events.ts +49 -0
  60. package/src/device-state/headingSource.ts +43 -8
  61. package/src/device-state/index.ts +3 -2
  62. package/src/device-state/replay.ts +76 -11
  63. package/src/device-state/spatialEvents.ts +300 -0
  64. package/src/geo.ts +23 -0
  65. package/src/maps/index.ts +81 -0
  66. package/src/maps/normalize.ts +225 -0
  67. package/src/vision/index.ts +4 -2
  68. package/dist/chunk-4XYXJYN5.mjs.map +0 -1
  69. package/dist/chunk-5HM6UA2K.mjs.map +0 -1
  70. package/dist/chunk-TZXWVYYR.mjs.map +0 -1
  71. package/dist/chunk-VQJPSLHP.mjs.map +0 -1
@@ -1,23 +1,25 @@
1
+ import {
2
+ createExpoOAuthProvider
3
+ } from "./chunk-L4V7OCJ3.mjs";
1
4
  import {
2
5
  createDeviceState,
3
6
  setupExpoProviders
4
- } from "./chunk-4XYXJYN5.mjs";
7
+ } from "./chunk-C7M5WAHA.mjs";
5
8
  import {
6
9
  createDeviceProvider
7
- } from "./chunk-5HM6UA2K.mjs";
8
- import "./chunk-TZXWVYYR.mjs";
10
+ } from "./chunk-GF2MPTAB.mjs";
11
+ import "./chunk-PCAEUX2N.mjs";
9
12
  import "./chunk-6LXF3JVX.mjs";
10
13
  import "./chunk-FF6ZZZXH.mjs";
11
14
  import {
12
15
  connectivity_exports,
13
16
  location_exports
14
- } from "./chunk-VQJPSLHP.mjs";
17
+ } from "./chunk-Z5AI2SXX.mjs";
15
18
  import "./chunk-KOXF2FZM.mjs";
16
19
  import "./chunk-XQSY6MHP.mjs";
17
20
  import "./chunk-4BMWVN25.mjs";
18
- import {
19
- createExpoOAuthProvider
20
- } from "./chunk-L4V7OCJ3.mjs";
21
+ import "./chunk-7FWYEHN5.mjs";
22
+ import "./chunk-J6XRNX7P.mjs";
21
23
  import "./chunk-WMJKH4XE.mjs";
22
24
 
23
25
  // src/bootstrap.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bootstrap.ts"],"sourcesContent":["/**\n * bootstrapExpoAdas — the single, self-contained SDK bootstrap (R10).\n *\n * The final high-level entry point of the \"fat SDK / thin shell\" arc: it folds\n * the ~15 hand-wired seams the host used to assemble in its own adas.ts into ONE\n * call, so the shell stops manually assembling platform providers/collectors/\n * plugins. Internally it initializes, in the order the migrated code established:\n * the Expo providers (haptics/bundle cache/clipboard/attachment cache + the\n * device-primitive provider), the host-bundled native plugins, the plugin-WebView\n * allow-list, native OAuth, the ACS reachability reporter, the L3 DeviceState\n * engine (with the SDK's OWN collectors — the shell injects none), the plugin/\n * UI-action navigator, and finally the core config+token bridge (initAdas).\n *\n * The API is DERIVED from the host's migrated adas.ts, not invented. Everything\n * the host still owns is passed in as a small values-and-getters bag: endpoint\n * getters (the host owns the dev/prod switch), the identity/token bridge, its\n * branded Google client id, its host-bundled plugin resolvers, the native\n * WebView module from its build, and its router callback.\n *\n * A SUBPATH (`@ateam-ai-mobile/expo/bootstrap`), like /device and /oauth: it\n * statically pulls the optional expo native modules (via createDeviceProvider /\n * the device-state collectors / the OAuth provider), so it must not sit on the\n * package's main entry, which a host without those modules still has to build.\n *\n * The two physical reasoning paths stay DISTINCT and are wired as SEPARATE\n * statements — never a merged bridge: LOCAL (the local tool registry + device\n * state the plugin/voice runtime reads) and SERVER (the relay allow-list here;\n * the DeviceBridge relay runtime itself is started by the host lifecycle, out of\n * this module-load bootstrap's scope).\n */\nimport { initAdas, setAcsReachabilityReporter, type TokenProvider, type AdasUser, type AdasSession } from '@ateam-ai-mobile/core';\nimport { setDeviceStateProvider, registerNativePlugin, registerPlatformDeviceTools, type RegisteredPlugin } from '@ateam-ai-mobile/plugin-runtime';\nimport { setOAuthProvider, setUIActionNavigator, setPluginWebViewExtraHosts, type UIActionRoute } from '@ateam-ai-mobile/ui';\n\nimport { setupExpoProviders, type ExpoAttachmentCache } from './index';\nimport { createDeviceProvider } from './device/createDeviceProvider';\nimport { createDeviceState } from './device-state';\nimport { createExpoOAuthProvider } from './oauth/expoOAuth';\nimport * as deviceConnectivity from './device-bridge/collectors/connectivity';\nimport * as deviceLocation from './device-bridge/collectors/location';\n\n/** A host-bundled native plugin: one lazy resolver registered under one or more ids. */\nexport interface NativePluginRegistration {\n resolver: () => Promise<RegisteredPlugin>;\n ids: string[];\n}\n\nexport interface BootstrapExpoAdasOptions {\n /**\n * Endpoint GETTERS — the host owns the dev/prod env switch, so these are read\n * live on every SDK request (never snapshotted). `core` is required; the rest\n * are optional (voice/consumer-auth features light up when present).\n */\n urls: {\n core: () => string;\n voice?: () => string;\n consumerAuth?: () => string;\n /** Trusted extra host for plugin WebViews (the relay device-bridge auth flows). */\n relay?: () => string;\n };\n /** The host's token bridge — outcome mapping (transient vs auth_failed) owned by the host. */\n tokenProvider: TokenProvider;\n /** Current user projection for chat routing (host reads its auth store). */\n getUser: () => AdasUser | null;\n /** Active tenant getter (signed-in tenant, falling back to the pre-auth pick). */\n tenant?: () => string;\n /** Adopt a freshly-minted session on tenant switch (host persists tenant-first, then logs in). */\n onSession?: (session: AdasSession) => void | Promise<void>;\n /** The host's bundled Google iOS client id, for the join/open-join OAuth path. */\n googleIosClientId?: string;\n /** Host-bundled native plugins (AuthWebView, ConnectionsPanel, …) — lazy resolvers. */\n nativePlugins?: NativePluginRegistration[];\n /** Native modules remote bundles may require() (e.g. react-native-webview) — from the host build. */\n bundleModules?: Record<string, unknown>;\n /** Pre-SDK AsyncStorage keys, so an existing install keeps its warm caches. */\n storageKeys?: { attachmentIndex?: string; bundleIndex?: string };\n /** Connectivity sink — the SDK reports fetch reachability up/down; the host feeds its banner. */\n onReachabilityChange?: (up: boolean) => void;\n /** Open the host's plugin screen for a UI-action chip (the host owns its router). */\n navigateToPlugin: (route: UIActionRoute) => void;\n /**\n * Reachability probe URL for the device-primitive connectivity API. The host\n * passes this EXPLICITLY (typically `${core}/health`) as a load-time snapshot —\n * deliberately NOT derived from `urls.core()`, so a dev/E2E core override does\n * not silently flow into the health probe (the asymmetry the host relied on).\n */\n reachabilityUrl?: string;\n}\n\n/**\n * Wire the entire Expo-backed ADAS platform in one call. Run for its side effect\n * at module load, before the router mounts. Returns the attachment cache so the\n * host can hand it to anything that needs it (initAdas already received it).\n */\nexport function bootstrapExpoAdas(opts: BootstrapExpoAdasOptions): { attachmentCache: ExpoAttachmentCache } {\n // Expo providers + the device-primitive implementation (props.device). The SDK\n // owns createDeviceProvider; the shell injects only its reachability URL.\n const { attachmentCache } = setupExpoProviders({\n bundleModules: opts.bundleModules,\n attachmentIndexKey: opts.storageKeys?.attachmentIndex,\n bundleIndexKey: opts.storageKeys?.bundleIndex,\n deviceProvider: createDeviceProvider({ reachabilityUrl: opts.reachabilityUrl }),\n });\n\n // Host-bundled native plugins: register each lazy resolver under its id aliases.\n for (const plugin of opts.nativePlugins ?? []) {\n for (const id of plugin.ids) registerNativePlugin(id, plugin.resolver);\n }\n\n // Plugin WebViews may navigate to the relay (device-bridge auth flows) —\n // whitelist it alongside core/voice. Getter → live across env switches.\n const relay = opts.urls.relay;\n setPluginWebViewExtraHosts(() => (relay ? [relay()] : []));\n\n // Native OAuth for the relocated auth screens (the ONLY native OAuth wiring).\n setOAuthProvider(createExpoOAuthProvider({ googleIosClientId: opts.googleIosClientId }));\n\n // ACS fetch outcomes feed the host's connectivity banner (any response = up,\n // thrown fetch = down). The host's sink stays host-side (lazy, no load cycle).\n if (opts.onReachabilityChange) {\n const onReach = opts.onReachabilityChange;\n setAcsReachabilityReporter({ up: () => onReach(true), down: () => onReach(false) });\n }\n\n // L3 DeviceState (props.deviceState) — the SEMANTIC layer, wired with the SDK's\n // OWN device-bridge collectors. The shell injects none (the R10 payoff): an\n // undeclared/unimplemented domain returns explicit `unknown`s, never a silent\n // undefined. Kept a SEPARATE statement from the SERVER relay — the two\n // reasoning paths never merge.\n setDeviceStateProvider(\n createDeviceState({ connectivity: deviceConnectivity, location: deviceLocation }),\n );\n\n // LOCAL device tools — register the static, host-owned platform tools\n // (device.echo / device.ping) at load, so the device path answers even before\n // any plugin bundle or sign-in: the platform tier deliberately does not depend\n // on the thing being proved. A tenant's EXTERNAL device tools load on\n // session-authenticated, which the host wires to its auth-session subscription\n // via syncDeviceToolsForSession() — ambient, not voice-triggered.\n registerPlatformDeviceTools();\n\n // Plugin/UI-action chips delegate navigation to the host's router.\n setUIActionNavigator(opts.navigateToPlugin);\n\n // Core config + token bridge. URL getters (not snapshots) so the env switch\n // flows through; identity/token bridge owned by the host.\n initAdas({\n coreUrl: opts.urls.core,\n ...(opts.urls.voice ? { voiceUrl: opts.urls.voice } : {}),\n ...(opts.urls.consumerAuth ? { consumerAuthUrl: opts.urls.consumerAuth } : {}),\n ...(opts.onSession ? { onSession: opts.onSession } : {}),\n ...(opts.tenant ? { tenant: opts.tenant } : {}),\n getUser: opts.getUser,\n tokenProvider: opts.tokenProvider,\n attachmentCache,\n });\n\n return { attachmentCache };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAS,UAAU,kCAAuF;AAC1G,SAAS,wBAAwB,sBAAsB,mCAA0D;AACjH,SAAS,kBAAkB,sBAAsB,kCAAsD;AA8DhG,SAAS,kBAAkB,MAA0E;AAG1G,QAAM,EAAE,gBAAgB,IAAI,mBAAmB;AAAA,IAC7C,eAAe,KAAK;AAAA,IACpB,oBAAoB,KAAK,aAAa;AAAA,IACtC,gBAAgB,KAAK,aAAa;AAAA,IAClC,gBAAgB,qBAAqB,EAAE,iBAAiB,KAAK,gBAAgB,CAAC;AAAA,EAChF,CAAC;AAGD,aAAW,UAAU,KAAK,iBAAiB,CAAC,GAAG;AAC7C,eAAW,MAAM,OAAO,IAAK,sBAAqB,IAAI,OAAO,QAAQ;AAAA,EACvE;AAIA,QAAM,QAAQ,KAAK,KAAK;AACxB,6BAA2B,MAAO,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAE;AAGzD,mBAAiB,wBAAwB,EAAE,mBAAmB,KAAK,kBAAkB,CAAC,CAAC;AAIvF,MAAI,KAAK,sBAAsB;AAC7B,UAAM,UAAU,KAAK;AACrB,+BAA2B,EAAE,IAAI,MAAM,QAAQ,IAAI,GAAG,MAAM,MAAM,QAAQ,KAAK,EAAE,CAAC;AAAA,EACpF;AAOA;AAAA,IACE,kBAAkB,EAAE,cAAc,sBAAoB,UAAU,iBAAe,CAAC;AAAA,EAClF;AAQA,8BAA4B;AAG5B,uBAAqB,KAAK,gBAAgB;AAI1C,WAAS;AAAA,IACP,SAAS,KAAK,KAAK;AAAA,IACnB,GAAI,KAAK,KAAK,QAAQ,EAAE,UAAU,KAAK,KAAK,MAAM,IAAI,CAAC;AAAA,IACvD,GAAI,KAAK,KAAK,eAAe,EAAE,iBAAiB,KAAK,KAAK,aAAa,IAAI,CAAC;AAAA,IAC5E,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;AAAA,IACtD,GAAI,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;AAAA,IAC7C,SAAS,KAAK;AAAA,IACd,eAAe,KAAK;AAAA,IACpB;AAAA,EACF,CAAC;AAED,SAAO,EAAE,gBAAgB;AAC3B;","names":[]}
1
+ {"version":3,"sources":["../src/bootstrap.ts"],"sourcesContent":["/**\n * bootstrapExpoAdas — the single, self-contained SDK bootstrap (R10).\n *\n * The final high-level entry point of the \"fat SDK / thin shell\" arc: it folds\n * the ~15 hand-wired seams the host used to assemble in its own adas.ts into ONE\n * call, so the shell stops manually assembling platform providers/collectors/\n * plugins. Internally it initializes, in the order the migrated code established:\n * the Expo providers (haptics/bundle cache/clipboard/attachment cache + the\n * device-primitive provider), the host-bundled native plugins, the plugin-WebView\n * allow-list, native OAuth, the ACS reachability reporter, the L3 DeviceState\n * engine (with the SDK's OWN collectors — the shell injects none), the plugin/\n * UI-action navigator, and finally the core config+token bridge (initAdas).\n *\n * The API is DERIVED from the host's migrated adas.ts, not invented. Everything\n * the host still owns is passed in as a small values-and-getters bag: endpoint\n * getters (the host owns the dev/prod switch), the identity/token bridge, its\n * branded Google client id, its host-bundled plugin resolvers, the native\n * WebView module from its build, and its router callback.\n *\n * A SUBPATH (`@ateam-ai-mobile/expo/bootstrap`), like /device and /oauth: it\n * statically pulls the optional expo native modules (via createDeviceProvider /\n * the device-state collectors / the OAuth provider), so it must not sit on the\n * package's main entry, which a host without those modules still has to build.\n *\n * The two physical reasoning paths stay DISTINCT and are wired as SEPARATE\n * statements — never a merged bridge: LOCAL (the local tool registry + device\n * state the plugin/voice runtime reads) and SERVER (the relay allow-list here;\n * the DeviceBridge relay runtime itself is started by the host lifecycle, out of\n * this module-load bootstrap's scope).\n */\nimport { initAdas, setAcsReachabilityReporter, type TokenProvider, type AdasUser, type AdasSession } from '@ateam-ai-mobile/core';\nimport { setDeviceStateProvider, registerNativePlugin, registerPlatformDeviceTools, type RegisteredPlugin } from '@ateam-ai-mobile/plugin-runtime';\nimport { setOAuthProvider, setUIActionNavigator, setPluginWebViewExtraHosts, type UIActionRoute } from '@ateam-ai-mobile/ui';\n\nimport { setupExpoProviders, type ExpoAttachmentCache } from './index';\nimport { createDeviceProvider } from './device/createDeviceProvider';\nimport { createDeviceState } from './device-state';\nimport { createExpoOAuthProvider } from './oauth/expoOAuth';\nimport * as deviceConnectivity from './device-bridge/collectors/connectivity';\nimport * as deviceLocation from './device-bridge/collectors/location';\n\n/** A host-bundled native plugin: one lazy resolver registered under one or more ids. */\nexport interface NativePluginRegistration {\n resolver: () => Promise<RegisteredPlugin>;\n ids: string[];\n}\n\nexport interface BootstrapExpoAdasOptions {\n /**\n * Endpoint GETTERS — the host owns the dev/prod env switch, so these are read\n * live on every SDK request (never snapshotted). `core` is required; the rest\n * are optional (voice/consumer-auth features light up when present).\n */\n urls: {\n core: () => string;\n voice?: () => string;\n consumerAuth?: () => string;\n /** Trusted extra host for plugin WebViews (the relay device-bridge auth flows). */\n relay?: () => string;\n };\n /** The host's token bridge — outcome mapping (transient vs auth_failed) owned by the host. */\n tokenProvider: TokenProvider;\n /** Current user projection for chat routing (host reads its auth store). */\n getUser: () => AdasUser | null;\n /** Active tenant getter (signed-in tenant, falling back to the pre-auth pick). */\n tenant?: () => string;\n /** Adopt a freshly-minted session on tenant switch (host persists tenant-first, then logs in). */\n onSession?: (session: AdasSession) => void | Promise<void>;\n /** The host's bundled Google iOS client id, for the join/open-join OAuth path. */\n googleIosClientId?: string;\n /** Host-bundled native plugins (AuthWebView, ConnectionsPanel, …) — lazy resolvers. */\n nativePlugins?: NativePluginRegistration[];\n /** Native modules remote bundles may require() (e.g. react-native-webview) — from the host build. */\n bundleModules?: Record<string, unknown>;\n /** Pre-SDK AsyncStorage keys, so an existing install keeps its warm caches. */\n storageKeys?: { attachmentIndex?: string; bundleIndex?: string };\n /** Connectivity sink — the SDK reports fetch reachability up/down; the host feeds its banner. */\n onReachabilityChange?: (up: boolean) => void;\n /** Open the host's plugin screen for a UI-action chip (the host owns its router). */\n navigateToPlugin: (route: UIActionRoute) => void;\n /**\n * Reachability probe URL for the device-primitive connectivity API. The host\n * passes this EXPLICITLY (typically `${core}/health`) as a load-time snapshot —\n * deliberately NOT derived from `urls.core()`, so a dev/E2E core override does\n * not silently flow into the health probe (the asymmetry the host relied on).\n */\n reachabilityUrl?: string;\n}\n\n/**\n * Wire the entire Expo-backed ADAS platform in one call. Run for its side effect\n * at module load, before the router mounts. Returns the attachment cache so the\n * host can hand it to anything that needs it (initAdas already received it).\n */\nexport function bootstrapExpoAdas(opts: BootstrapExpoAdasOptions): { attachmentCache: ExpoAttachmentCache } {\n // Expo providers + the device-primitive implementation (props.device). The SDK\n // owns createDeviceProvider; the shell injects only its reachability URL.\n const { attachmentCache } = setupExpoProviders({\n bundleModules: opts.bundleModules,\n attachmentIndexKey: opts.storageKeys?.attachmentIndex,\n bundleIndexKey: opts.storageKeys?.bundleIndex,\n deviceProvider: createDeviceProvider({ reachabilityUrl: opts.reachabilityUrl }),\n });\n\n // Host-bundled native plugins: register each lazy resolver under its id aliases.\n for (const plugin of opts.nativePlugins ?? []) {\n for (const id of plugin.ids) registerNativePlugin(id, plugin.resolver);\n }\n\n // Plugin WebViews may navigate to the relay (device-bridge auth flows) —\n // whitelist it alongside core/voice. Getter → live across env switches.\n const relay = opts.urls.relay;\n setPluginWebViewExtraHosts(() => (relay ? [relay()] : []));\n\n // Native OAuth for the relocated auth screens (the ONLY native OAuth wiring).\n setOAuthProvider(createExpoOAuthProvider({ googleIosClientId: opts.googleIosClientId }));\n\n // ACS fetch outcomes feed the host's connectivity banner (any response = up,\n // thrown fetch = down). The host's sink stays host-side (lazy, no load cycle).\n if (opts.onReachabilityChange) {\n const onReach = opts.onReachabilityChange;\n setAcsReachabilityReporter({ up: () => onReach(true), down: () => onReach(false) });\n }\n\n // L3 DeviceState (props.deviceState) — the SEMANTIC layer, wired with the SDK's\n // OWN device-bridge collectors. The shell injects none (the R10 payoff): an\n // undeclared/unimplemented domain returns explicit `unknown`s, never a silent\n // undefined. Kept a SEPARATE statement from the SERVER relay — the two\n // reasoning paths never merge.\n setDeviceStateProvider(\n createDeviceState({ connectivity: deviceConnectivity, location: deviceLocation }),\n );\n\n // LOCAL device tools — register the static, host-owned platform tools\n // (device.echo / device.ping) at load, so the device path answers even before\n // any plugin bundle or sign-in: the platform tier deliberately does not depend\n // on the thing being proved. A tenant's EXTERNAL device tools load on\n // session-authenticated, which the host wires to its auth-session subscription\n // via syncDeviceToolsForSession() — ambient, not voice-triggered.\n registerPlatformDeviceTools();\n\n // Plugin/UI-action chips delegate navigation to the host's router.\n setUIActionNavigator(opts.navigateToPlugin);\n\n // Core config + token bridge. URL getters (not snapshots) so the env switch\n // flows through; identity/token bridge owned by the host.\n initAdas({\n coreUrl: opts.urls.core,\n ...(opts.urls.voice ? { voiceUrl: opts.urls.voice } : {}),\n ...(opts.urls.consumerAuth ? { consumerAuthUrl: opts.urls.consumerAuth } : {}),\n ...(opts.onSession ? { onSession: opts.onSession } : {}),\n ...(opts.tenant ? { tenant: opts.tenant } : {}),\n getUser: opts.getUser,\n tokenProvider: opts.tokenProvider,\n attachmentCache,\n });\n\n return { attachmentCache };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAS,UAAU,kCAAuF;AAC1G,SAAS,wBAAwB,sBAAsB,mCAA0D;AACjH,SAAS,kBAAkB,sBAAsB,kCAAsD;AA8DhG,SAAS,kBAAkB,MAA0E;AAG1G,QAAM,EAAE,gBAAgB,IAAI,mBAAmB;AAAA,IAC7C,eAAe,KAAK;AAAA,IACpB,oBAAoB,KAAK,aAAa;AAAA,IACtC,gBAAgB,KAAK,aAAa;AAAA,IAClC,gBAAgB,qBAAqB,EAAE,iBAAiB,KAAK,gBAAgB,CAAC;AAAA,EAChF,CAAC;AAGD,aAAW,UAAU,KAAK,iBAAiB,CAAC,GAAG;AAC7C,eAAW,MAAM,OAAO,IAAK,sBAAqB,IAAI,OAAO,QAAQ;AAAA,EACvE;AAIA,QAAM,QAAQ,KAAK,KAAK;AACxB,6BAA2B,MAAO,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAE;AAGzD,mBAAiB,wBAAwB,EAAE,mBAAmB,KAAK,kBAAkB,CAAC,CAAC;AAIvF,MAAI,KAAK,sBAAsB;AAC7B,UAAM,UAAU,KAAK;AACrB,+BAA2B,EAAE,IAAI,MAAM,QAAQ,IAAI,GAAG,MAAM,MAAM,QAAQ,KAAK,EAAE,CAAC;AAAA,EACpF;AAOA;AAAA,IACE,kBAAkB,EAAE,cAAc,sBAAoB,UAAU,iBAAe,CAAC;AAAA,EAClF;AAQA,8BAA4B;AAG5B,uBAAqB,KAAK,gBAAgB;AAI1C,WAAS;AAAA,IACP,SAAS,KAAK,KAAK;AAAA,IACnB,GAAI,KAAK,KAAK,QAAQ,EAAE,UAAU,KAAK,KAAK,MAAM,IAAI,CAAC;AAAA,IACvD,GAAI,KAAK,KAAK,eAAe,EAAE,iBAAiB,KAAK,KAAK,aAAa,IAAI,CAAC;AAAA,IAC5E,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;AAAA,IACtD,GAAI,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;AAAA,IAC7C,SAAS,KAAK;AAAA,IACd,eAAe,KAAK;AAAA,IACpB;AAAA,EACF,CAAC;AAED,SAAO,EAAE,gBAAgB;AAC3B;","names":[]}
@@ -0,0 +1,203 @@
1
+ import {
2
+ distanceOf
3
+ } from "./chunk-J6XRNX7P.mjs";
4
+
5
+ // src/maps/index.ts
6
+ import { Platform } from "react-native";
7
+ import { requireOptionalNativeModule } from "expo-modules-core";
8
+ import * as ExpoLocation from "expo-location";
9
+
10
+ // src/args.ts
11
+ var shown = (v) => {
12
+ let s;
13
+ try {
14
+ s = JSON.stringify(v, (_k, x) => typeof x === "number" && !Number.isFinite(x) ? `${x}` : x)?.replace(/"\\u0001(NaN|-?Infinity)\\u0001"/g, "$1");
15
+ } catch {
16
+ }
17
+ s = s ?? String(v);
18
+ return s.length > 80 ? `${s.slice(0, 77)}...` : s;
19
+ };
20
+ function refuseArgument(capability, verb, problem, nothing) {
21
+ const e = new Error(`${capability}.${verb}: ${problem}; ${nothing}.`);
22
+ e.code = "INVALID_ARGUMENT";
23
+ return e;
24
+ }
25
+ function countArg(capability, verb, name, value, def, max, nothing) {
26
+ const v = value ?? def;
27
+ if (typeof v !== "number" || !Number.isFinite(v) || v < 1) {
28
+ throw refuseArgument(capability, verb, `${name} must be a number from 1 (at most ${max} are used), not ${shown(value)}`, nothing);
29
+ }
30
+ return Math.min(max, Math.floor(v));
31
+ }
32
+ function fractionArg(capability, verb, name, value, def, nothing) {
33
+ const v = value ?? def;
34
+ if (typeof v !== "number" || !Number.isFinite(v) || v < 0 || v > 1) {
35
+ throw refuseArgument(capability, verb, `${name} must be a number from 0 to 1, not ${shown(value)}`, nothing);
36
+ }
37
+ return v;
38
+ }
39
+
40
+ // src/maps/normalize.ts
41
+ var SEARCH_RADIUS_DEFAULT_M = 3e3;
42
+ var SEARCH_RADIUS_MAX_M = 1e5;
43
+ var SEARCH_LIMIT_DEFAULT = 8;
44
+ var SEARCH_LIMIT_MAX = 25;
45
+ var text = (v) => typeof v === "string" && v.trim() !== "" ? v : null;
46
+ var refuseArgument2 = (verb, problem, nothing) => refuseArgument("maps", verb, problem, nothing);
47
+ function coordinateArg(verb, name, value, nothing) {
48
+ const c = value;
49
+ const latitude = c?.latitude, longitude = c?.longitude;
50
+ if (typeof latitude === "number" && Number.isFinite(latitude) && Math.abs(latitude) <= 90 && typeof longitude === "number" && Number.isFinite(longitude) && Math.abs(longitude) <= 180) {
51
+ return { latitude, longitude };
52
+ }
53
+ throw refuseArgument2(
54
+ verb,
55
+ `${name} must be { latitude, longitude } numbers (latitude -90..90, longitude -180..180), not ${shown(value)}`,
56
+ nothing
57
+ );
58
+ }
59
+ function searchArgs(query, opts) {
60
+ const nothing = "nothing was searched";
61
+ if (typeof query !== "string" || query.trim() === "") {
62
+ throw refuseArgument2("search", `query must be a non-empty string, not ${shown(query)}`, nothing);
63
+ }
64
+ const near = opts?.near == null ? null : coordinateArg("search", "near", opts.near, nothing);
65
+ const radiusM = opts?.radiusM ?? SEARCH_RADIUS_DEFAULT_M;
66
+ if (typeof radiusM !== "number" || !(radiusM > 0 && radiusM <= SEARCH_RADIUS_MAX_M)) {
67
+ throw refuseArgument2(
68
+ "search",
69
+ `radiusM must be metres above 0 and at most ${SEARCH_RADIUS_MAX_M}, not ${shown(radiusM)}`,
70
+ nothing
71
+ );
72
+ }
73
+ const limit = countArg("maps", "search", "limit", opts?.limit, SEARCH_LIMIT_DEFAULT, SEARCH_LIMIT_MAX, nothing);
74
+ return { query, near, radiusM, limit };
75
+ }
76
+ var point = (c) => ({
77
+ latitude: Number(c.latitude),
78
+ longitude: Number(c.longitude)
79
+ });
80
+ function toMapsAddress(raw) {
81
+ const r = raw ?? {};
82
+ return {
83
+ name: text(r.name),
84
+ street: text(r.street),
85
+ streetNumber: text(r.streetNumber),
86
+ district: text(r.district),
87
+ city: text(r.city),
88
+ region: text(r.region),
89
+ postalCode: text(r.postalCode),
90
+ country: text(r.country),
91
+ isoCountryCode: text(r.isoCountryCode)
92
+ };
93
+ }
94
+ function toMapsCategory(raw) {
95
+ const c = text(raw);
96
+ return c ? c.replace(/^MKPOICategory/, "") || null : null;
97
+ }
98
+ function toMapsPlaces(raw, near) {
99
+ return (raw ?? []).map((r) => {
100
+ const coordinate = point(r);
101
+ return {
102
+ name: text(r.name),
103
+ coordinate,
104
+ address: toMapsAddress(r.address),
105
+ category: toMapsCategory(r.category),
106
+ distanceM: near ? distanceOf([near, coordinate]) : null
107
+ };
108
+ });
109
+ }
110
+ function toReverseGeocodedPlace(at, address) {
111
+ return {
112
+ name: address.name,
113
+ coordinate: point(at),
114
+ address,
115
+ category: null,
116
+ distanceM: null
117
+ };
118
+ }
119
+ function toMapsRoute(raw) {
120
+ const steps = (raw.steps ?? []).map((s) => ({
121
+ instructions: typeof s.instructions === "string" ? s.instructions : "",
122
+ distanceM: Number(s.distance),
123
+ notice: text(s.notice),
124
+ polyline: (s.polyline ?? []).map(point)
125
+ }));
126
+ return {
127
+ mode: "walking",
128
+ distanceM: Number(raw.distance),
129
+ expectedTravelTimeMs: Math.round(Number(raw.expectedTravelTime) * 1e3),
130
+ steps,
131
+ polyline: (raw.polyline ?? []).map(point)
132
+ };
133
+ }
134
+ function mapsFailure(verb, err) {
135
+ const nativeCode = String(err?.code ?? "");
136
+ const detail = String(err?.message ?? err ?? "").trim();
137
+ let code;
138
+ let why;
139
+ if (nativeCode === "THROTTLED") {
140
+ code = "THROTTLED";
141
+ why = "Apple is rate-limiting map requests from this app \u2014 wait before retrying";
142
+ } else if (nativeCode === "OFFLINE") {
143
+ code = "OFFLINE";
144
+ why = "the map service could not be reached \u2014 the phone may be offline";
145
+ } else if (nativeCode === "ERR_GEOCODING_NETWORK") {
146
+ code = "OFFLINE";
147
+ why = "the geocoder could not be reached \u2014 the phone may be offline, or Apple is rate-limiting requests (iOS reports both the same way)";
148
+ } else {
149
+ code = "UNAVAILABLE";
150
+ why = "the map service failed";
151
+ }
152
+ const failure = new Error(
153
+ `maps.${verb} could not look: ${why}. This is not "found nothing".` + (detail ? ` (${nativeCode ? nativeCode + ": " : ""}${detail})` : "")
154
+ );
155
+ failure.code = code;
156
+ return failure;
157
+ }
158
+
159
+ // src/maps/index.ts
160
+ var native = requireOptionalNativeModule("AdaMaps");
161
+ function missingReason() {
162
+ if (Platform.OS !== "ios") return `iOS (Apple MapKit) \u2014 ${Platform.OS} has no implementation yet`;
163
+ if (!native) return "the app build with the AdaMaps module (this build predates it \u2014 a native rebuild is needed)";
164
+ return null;
165
+ }
166
+ function isSupported() {
167
+ try {
168
+ return missingReason() === null && (native?.isSupported() ?? false);
169
+ } catch {
170
+ return false;
171
+ }
172
+ }
173
+ async function search(query, near, radiusM, limit) {
174
+ if (!native) throw new Error("ada-maps native module not present in this build");
175
+ return near ? native.search(query, near.latitude, near.longitude, true, radiusM, limit) : native.search(query, 0, 0, false, radiusM, limit);
176
+ }
177
+ async function route(from, to) {
178
+ if (!native) throw new Error("ada-maps native module not present in this build");
179
+ return native.route(from.latitude, from.longitude, to.latitude, to.longitude);
180
+ }
181
+ async function reverseGeocode(at) {
182
+ const [first] = await ExpoLocation.reverseGeocodeAsync({ latitude: at.latitude, longitude: at.longitude });
183
+ return first ? toMapsAddress(first) : null;
184
+ }
185
+
186
+ export {
187
+ shown,
188
+ refuseArgument,
189
+ countArg,
190
+ fractionArg,
191
+ coordinateArg,
192
+ searchArgs,
193
+ toMapsPlaces,
194
+ toReverseGeocodedPlace,
195
+ toMapsRoute,
196
+ mapsFailure,
197
+ missingReason,
198
+ isSupported,
199
+ search,
200
+ route,
201
+ reverseGeocode
202
+ };
203
+ //# sourceMappingURL=chunk-7FWYEHN5.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/maps/index.ts","../src/args.ts","../src/maps/normalize.ts"],"sourcesContent":["// ada-maps — place search + walking directions (Apple MapKit), our own native\n// code, plus the SDK's one reverse geocode.\n//\n// NOT on-device — the opposite of ada-vision. Every call sends the query and the\n// coordinates it is given to a map service over the network. None of it reads\n// the device's location: the caller supplies every coordinate.\n//\n// search(...) — MKLocalSearch (AdaMaps module, iOS only)\n// route(...) — MKDirections (AdaMaps module, iOS only)\n// reverseGeocode(at) — expo-location's reverseGeocodeAsync, which IS CLGeocoder\n// on iOS and the platform Geocoder on Android. No Swift for\n// it, and the ONLY reverse geocode in the SDK: the location\n// collector and the connector bridge call this too.\n//\n// requireOptionalNativeModule: on a binary WITHOUT the module the import is null,\n// isSupported() is false, and search/route refuse cleanly (no crash). Android has\n// no AdaMaps at all, so it refuses by name the same way.\n\nimport { Platform } from 'react-native';\nimport { requireOptionalNativeModule } from 'expo-modules-core';\nimport * as ExpoLocation from 'expo-location';\nimport type { MapsAddress, MapsCoordinate } from '@ateam-ai-mobile/plugin-runtime';\nimport { toMapsAddress } from './normalize';\nimport type { RawMapsPlace, RawMapsRoute } from './normalize';\n\ninterface AdaMapsNative {\n isSupported(): boolean;\n search(query: string, lat: number, lng: number, hasNear: boolean, radiusM: number, limit: number): Promise<RawMapsPlace[]>;\n route(fromLat: number, fromLng: number, toLat: number, toLng: number): Promise<RawMapsRoute | null>;\n}\n\nconst native = requireOptionalNativeModule<AdaMapsNative>('AdaMaps');\n\n/** What search/route are missing in THIS build, as the clause after \"needs\" —\n * or null when they can run. A voice assistant reads it out, so it names the\n * missing thing rather than giving a code. */\nexport function missingReason(): string | null {\n if (Platform.OS !== 'ios') return `iOS (Apple MapKit) — ${Platform.OS} has no implementation yet`;\n if (!native) return 'the app build with the AdaMaps module (this build predates it — a native rebuild is needed)';\n return null;\n}\n\n/** Is the native maps module present in this binary (and on a platform it runs on)? */\nexport function isSupported(): boolean {\n try { return missingReason() === null && (native?.isSupported() ?? false); } catch { return false; }\n}\n\n// search/route hand their arguments to native AS GIVEN: a NaN or Infinity\n// `limit` traps Swift's Int conversion and kills the app. createMapsAPI checks\n// every argument first (searchArgs / coordinateArg in ./normalize); a host\n// calling these directly must pass what those checks would accept.\n\n/** MKLocalSearch around `near` (when given). [] = looked, found nothing; throws =\n * couldn't look, with a string code OFFLINE / THROTTLED / UNAVAILABLE. */\nexport async function search(\n query: string,\n near: MapsCoordinate | null,\n radiusM: number,\n limit: number,\n): Promise<RawMapsPlace[]> {\n if (!native) throw new Error('ada-maps native module not present in this build');\n // Without `near`, hasNear is false and Swift never reads lat/lng — the zeros\n // are placeholders for a primitive argument, not a place.\n return near\n ? native.search(query, near.latitude, near.longitude, true, radiusM, limit)\n : native.search(query, 0, 0, false, radiusM, limit);\n}\n\n/** MKDirections, walking, between two caller-supplied points. null = no route. */\nexport async function route(from: MapsCoordinate, to: MapsCoordinate): Promise<RawMapsRoute | null> {\n if (!native) throw new Error('ada-maps native module not present in this build');\n return native.route(from.latitude, from.longitude, to.latitude, to.longitude);\n}\n\n/** The address at a coordinate, or null when the geocoder has nothing there.\n * Throws when it could not look (network, rate limit, Android without location\n * permission) — callers decide whether that is fatal. */\nexport async function reverseGeocode(at: MapsCoordinate): Promise<MapsAddress | null> {\n const [first] = await ExpoLocation.reverseGeocodeAsync({ latitude: at.latitude, longitude: at.longitude });\n return first ? toMapsAddress(first) : null;\n}\n","// Argument checks for native verbs — one place, shared by every capability that\n// hands caller numbers to Swift.\n//\n// Why this exists: expo-modules-core converts a JS number to a Swift Int with\n// `Int(double.rounded())`, which TRAPS on NaN, ±Infinity or anything past\n// Int.max. A plugin (or a model driving a device tool) passing `limit: Infinity`\n// or `maxItems: NaN` would therefore kill the host app. Every count that crosses\n// the bridge is checked here first and refused BY NAME instead.\n//\n// No imports on purpose: it runs under plain `node --test`.\n\n/** A malformed call, refused before anything is sent. Retrying will not help;\n * fixing the call will. */\nexport type ArgumentError = Error & { code: 'INVALID_ARGUMENT' };\n\n/** What the caller passed, short enough to quote back in a refusal. NaN and\n * Infinity are spelled out, unquoted (JSON would print them as null). */\nexport const shown = (v: unknown): string => {\n let s: string | undefined;\n try {\n s = JSON.stringify(v, (_k, x) => (typeof x === 'number' && !Number.isFinite(x) ? `\\u0001${x}\\u0001` : x))\n ?.replace(/\"\\\\u0001(NaN|-?Infinity)\\\\u0001\"/g, '$1');\n } catch { /* cyclic — fall back to String */ }\n s = s ?? String(v);\n return s.length > 80 ? `${s.slice(0, 77)}...` : s;\n};\n\n/** `<capability>.<verb>: <problem>; <what was not done>.` with code INVALID_ARGUMENT. */\nexport function refuseArgument(capability: string, verb: string, problem: string, nothing: string): ArgumentError {\n const e = new Error(`${capability}.${verb}: ${problem}; ${nothing}.`) as ArgumentError;\n e.code = 'INVALID_ARGUMENT';\n return e;\n}\n\n/** A count bound for a Swift Int: absent → `def`; otherwise a finite number ≥ 1,\n * floored and capped at `max`. Anything else refuses by name. */\nexport function countArg(\n capability: string, verb: string, name: string, value: unknown, def: number, max: number, nothing: string,\n): number {\n const v = value ?? def;\n if (typeof v !== 'number' || !Number.isFinite(v) || v < 1) {\n throw refuseArgument(capability, verb, `${name} must be a number from 1 (at most ${max} are used), not ${shown(value)}`, nothing);\n }\n return Math.min(max, Math.floor(v));\n}\n\n/** A 0..1 fraction (a confidence): absent → `def`; NaN or out of range refuses. */\nexport function fractionArg(\n capability: string, verb: string, name: string, value: unknown, def: number, nothing: string,\n): number {\n const v = value ?? def;\n if (typeof v !== 'number' || !Number.isFinite(v) || v < 0 || v > 1) {\n throw refuseArgument(capability, verb, `${name} must be a number from 0 to 1, not ${shown(value)}`, nothing);\n }\n return v;\n}\n","// Pure shaping for native.maps — no Expo, no React Native, so it runs under\n// plain `node --test` (tests/adaMapsNormalize.test.mjs pins it).\n//\n// The native side hands back loose dictionaries — AdaMaps (MapKit) for search\n// and route, expo-location's geocoder for reverse geocoding. This turns them\n// into the typed MapsAPI shapes, and one set of failure codes. Unknown is\n// `null`, never '' or 0: an empty street reads as a street with no name, and a\n// 0 m route reads as \"you have arrived\".\n//\n// It also checks what a caller sends BEFORE it crosses the bridge (searchArgs,\n// coordinateArg). A remote bundle is plain JS at runtime, so the types promise\n// nothing: a NaN or Infinity `limit` traps Swift's Int conversion and kills the\n// app, and a `{ lat, lng }` near would search around 0,0 and answer \"found\n// nothing\" with confidence.\n\nimport type {\n MapsAddress,\n MapsCoordinate,\n MapsPlace,\n MapsRoute,\n MapsRouteStep,\n} from '@ateam-ai-mobile/plugin-runtime';\nimport { distanceOf } from '../geo';\nimport { countArg, refuseArgument as refuse, shown, type ArgumentError } from '../args';\n\n/** An address as the native geocoders spell it. AdaMaps sends exactly these\n * keys; expo-location sends these plus `subregion`/`timezone`/\n * `formattedAddress`, which MapsAddress does not carry. */\nexport interface RawMapsAddress {\n name?: string | null;\n street?: string | null;\n streetNumber?: string | null;\n district?: string | null;\n city?: string | null;\n region?: string | null;\n postalCode?: string | null;\n country?: string | null;\n isoCountryCode?: string | null;\n}\n\n/** One AdaMaps search hit (AdaMapsModule.place). */\nexport interface RawMapsPlace {\n name: string | null;\n latitude: number;\n longitude: number;\n /** MKPointOfInterestCategory raw value, e.g. \"MKPOICategoryPharmacy\". */\n category: string | null;\n address: RawMapsAddress;\n}\n\n/** An AdaMaps walking route (AdaMapsModule.route) — distances in metres,\n * expectedTravelTime in SECONDS, as MapKit reports them. */\nexport interface RawMapsRoute {\n distance: number;\n expectedTravelTime: number;\n steps: Array<{ instructions: string | null; distance: number; notice: string | null; polyline: MapsCoordinate[] }>;\n polyline: MapsCoordinate[];\n}\n\n/** The three ways a maps call can fail to look — see MapsAPI. */\nexport type MapsFailureCode = 'UNAVAILABLE' | 'OFFLINE' | 'THROTTLED';\n\n/** A malformed call, refused before anything is sent. Not a fourth way to fail\n * to look: retrying will not help, fixing the call will. */\nexport type MapsArgumentError = ArgumentError;\n\nconst SEARCH_RADIUS_DEFAULT_M = 3000;\n/** Keeps the region MapKit is handed a small, valid one. A \"near\" search wider\n * than this is a different question. */\nconst SEARCH_RADIUS_MAX_M = 100_000;\nconst SEARCH_LIMIT_DEFAULT = 8;\nconst SEARCH_LIMIT_MAX = 25;\n\nconst text = (v: unknown): string | null =>\n typeof v === 'string' && v.trim() !== '' ? v : null;\n\nconst refuseArgument = (verb: string, problem: string, nothing: string): MapsArgumentError =>\n refuse('maps', verb, problem, nothing);\n\n/** A caller's coordinate, checked and copied to exactly `{ latitude, longitude }`.\n * Anything else — `{ lat, lng }`, strings, NaN, out of range — refuses BY NAME\n * rather than being sent as 0,0 or NaN. */\nexport function coordinateArg(verb: string, name: string, value: unknown, nothing: string): MapsCoordinate {\n const c = value as { latitude?: unknown; longitude?: unknown } | null | undefined;\n const latitude = c?.latitude, longitude = c?.longitude;\n if (\n typeof latitude === 'number' && Number.isFinite(latitude) && Math.abs(latitude) <= 90 &&\n typeof longitude === 'number' && Number.isFinite(longitude) && Math.abs(longitude) <= 180\n ) {\n return { latitude, longitude };\n }\n throw refuseArgument(\n verb,\n `${name} must be { latitude, longitude } numbers (latitude -90..90, longitude -180..180), not ${shown(value)}`,\n nothing,\n );\n}\n\n/** search's arguments, checked and defaulted (radiusM 3000, limit 8). `limit`\n * is floored and capped at 25; everything else out of range refuses. */\nexport function searchArgs(\n query: unknown,\n opts: { near?: unknown; radiusM?: unknown; limit?: unknown } | null | undefined,\n): { query: string; near: MapsCoordinate | null; radiusM: number; limit: number } {\n const nothing = 'nothing was searched';\n if (typeof query !== 'string' || query.trim() === '') {\n throw refuseArgument('search', `query must be a non-empty string, not ${shown(query)}`, nothing);\n }\n const near = opts?.near == null ? null : coordinateArg('search', 'near', opts.near, nothing);\n const radiusM = opts?.radiusM ?? SEARCH_RADIUS_DEFAULT_M;\n if (typeof radiusM !== 'number' || !(radiusM > 0 && radiusM <= SEARCH_RADIUS_MAX_M)) {\n throw refuseArgument(\n 'search', `radiusM must be metres above 0 and at most ${SEARCH_RADIUS_MAX_M}, not ${shown(radiusM)}`, nothing);\n }\n const limit = countArg('maps', 'search', 'limit', opts?.limit, SEARCH_LIMIT_DEFAULT, SEARCH_LIMIT_MAX, nothing);\n return { query, near, radiusM, limit };\n}\n\nconst point = (c: MapsCoordinate): MapsCoordinate => ({\n latitude: Number(c.latitude),\n longitude: Number(c.longitude),\n});\n\nexport function toMapsAddress(raw: RawMapsAddress | null | undefined): MapsAddress {\n const r = raw ?? {};\n return {\n name: text(r.name),\n street: text(r.street),\n streetNumber: text(r.streetNumber),\n district: text(r.district),\n city: text(r.city),\n region: text(r.region),\n postalCode: text(r.postalCode),\n country: text(r.country),\n isoCountryCode: text(r.isoCountryCode),\n };\n}\n\n/** \"MKPOICategoryPharmacy\" → \"Pharmacy\": the vocabulary term, without the\n * framework's prefix. */\nexport function toMapsCategory(raw: unknown): string | null {\n const c = text(raw);\n return c ? c.replace(/^MKPOICategory/, '') || null : null;\n}\n\n/** Search hits → places. `distanceM` is straight-line from `near`, and only\n * when the caller gave one — a distance from nowhere would be invented. */\nexport function toMapsPlaces(raw: RawMapsPlace[] | null | undefined, near: MapsCoordinate | null): MapsPlace[] {\n return (raw ?? []).map(r => {\n const coordinate = point(r);\n return {\n name: text(r.name),\n coordinate,\n address: toMapsAddress(r.address),\n category: toMapsCategory(r.category),\n distanceM: near ? distanceOf([near, coordinate]) : null,\n };\n });\n}\n\n/** A reverse-geocoded address → a place AT the point asked about. The platform\n * geocoder returns an address, not a snapped point or a category. */\nexport function toReverseGeocodedPlace(at: MapsCoordinate, address: MapsAddress): MapsPlace {\n return {\n name: address.name,\n coordinate: point(at),\n address,\n category: null,\n distanceM: null,\n };\n}\n\n/** A MapKit route → MapsRoute. Seconds become ms; every step is kept, including\n * Apple's empty-instruction origin step, so indexes match Apple's. */\nexport function toMapsRoute(raw: RawMapsRoute): MapsRoute {\n const steps: MapsRouteStep[] = (raw.steps ?? []).map(s => ({\n instructions: typeof s.instructions === 'string' ? s.instructions : '',\n distanceM: Number(s.distance),\n notice: text(s.notice),\n polyline: (s.polyline ?? []).map(point),\n }));\n return {\n mode: 'walking',\n distanceM: Number(raw.distance),\n expectedTravelTimeMs: Math.round(Number(raw.expectedTravelTime) * 1000),\n steps,\n polyline: (raw.polyline ?? []).map(point),\n };\n}\n\n/**\n * A native rejection → an Error whose `code` is one of MapsAPI's three.\n *\n * AdaMaps already rejects with OFFLINE / THROTTLED / UNAVAILABLE. expo-location\n * (reverseGeocode) has its own codes: on iOS a CLError.network becomes\n * ERR_GEOCODING_NETWORK, which Apple uses for BOTH a lost connection and a rate\n * limit — so it maps to OFFLINE and the message says it may be either. Anything\n * else is UNAVAILABLE, with the platform's own words kept beside ours.\n */\nexport function mapsFailure(verb: string, err: unknown): Error & { code: MapsFailureCode } {\n const nativeCode = String((err as any)?.code ?? '');\n const detail = String((err as any)?.message ?? err ?? '').trim();\n let code: MapsFailureCode;\n let why: string;\n if (nativeCode === 'THROTTLED') {\n code = 'THROTTLED';\n why = 'Apple is rate-limiting map requests from this app — wait before retrying';\n } else if (nativeCode === 'OFFLINE') {\n code = 'OFFLINE';\n why = 'the map service could not be reached — the phone may be offline';\n } else if (nativeCode === 'ERR_GEOCODING_NETWORK') {\n code = 'OFFLINE';\n why = 'the geocoder could not be reached — the phone may be offline, or Apple is ' +\n 'rate-limiting requests (iOS reports both the same way)';\n } else {\n code = 'UNAVAILABLE';\n why = 'the map service failed';\n }\n const failure = new Error(\n `maps.${verb} could not look: ${why}. This is not \"found nothing\".` +\n (detail ? ` (${nativeCode ? nativeCode + ': ' : ''}${detail})` : ''),\n ) as Error & { code: MapsFailureCode };\n failure.code = code;\n return failure;\n}\n"],"mappings":"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","names":["refuseArgument"]}