import { jseComm } from './jseComm' // List of feature that the SDK supports const featureFlags = { selfTracking: true // ARX need to start tracking manually when needs it } interface DynamicObject { [key: string]: any; } const reactive: DynamicObject = {} let isLoaded = false enum DeeplinkSupportedEnum { UNKNOWN, SUPPORTED, UNSUPPORTED } let isDeeplinkSupportedCache = DeeplinkSupportedEnum.UNKNOWN interface DynamicCbObject { [key: string]: Array<(value: any) => void> } const reactiveCB: DynamicCbObject = {} jseComm.export({ vera: { reactiveData: (reactiveData: object) => { Object.assign(reactive, reactiveData) Object.entries(reactiveData).forEach(([key, value]: [string, string]) => { reactiveCB[key]?.forEach((cb) => { cb(value) }) }) } } }) function loaded (): void { isLoaded = true jseComm.dispatch({ funcName: 'loaded', params: { featureFlags }, returnType: false }) } interface AppConfig { _id: string, [key: string]: any // Every app has different attributes } async function getAppConfig (): Promise { return await jseComm.dispatch({ funcName: 'getAppConfig', params: {}, returnType: true }) } interface Building { floors: Array buildingId: string, label: string, polyhedron: object } interface SvgMaps { minBoundingBox: {[key: string]: number }, maxBoundingBox: {[key: string]: number }, floorNum: number, svgMapPath: string, buildingIndex: number, cellSize: number, label: string } interface SiteConfig { buildings: Array, siteId: string, svgMaps: Array // Every app has different attributes } type POI = { id: string position: [number, number, number] text: string image: string } async function getSiteConfig (): Promise { return await jseComm.dispatch({ funcName: 'getSiteConfig', params: {}, returnType: true }) } async function isDeeplinkSupported (): Promise { if (isDeeplinkSupportedCache !== DeeplinkSupportedEnum.UNKNOWN) { return isDeeplinkSupportedCache === DeeplinkSupportedEnum.SUPPORTED } const isSupported = await jseComm.dispatch({ funcName: 'isDeeplinkSupported', params: {}, returnType: true }) isDeeplinkSupportedCache = isSupported ? DeeplinkSupportedEnum.SUPPORTED : DeeplinkSupportedEnum.UNSUPPORTED return isSupported } async function getNewDeeplink ({ data, isValidOnlyForThisSite }: { data: object, isValidOnlyForThisSite: boolean }): Promise { return await jseComm.dispatch({ funcName: 'getNewDeeplink', params: { data, isValidOnlyForThisSite }, returnType: true }) } /** * @deprecated Use querySemanticObjects instead. */ async function getSOArProperties ({ key }: { key: string }): Promise { console.warn('getSOArProperties is obsolete, get your own SOs using "querySemanticObjects"') return await jseComm.dispatch({ funcName: 'getSOArProperties', params: { key }, returnType: true }) } function addSharedPoi ({ id, position, text, image }: POI): void { jseComm.dispatch({ funcName: 'addSharedPoi', params: { id, position, text, image }, returnType: false }) } function removeSharedPoi ({ id }: { id: string }): void { jseComm.dispatch({ funcName: 'removeSharedPoi', params: { id }, returnType: false }) } // TODO: (yoav) support returning a function #16235 async function subscribeToSharedPois ({ id, cb, unsubscribe }: { id: string, cb: ({ pois }: { pois: Array }) => void, unsubscribe: boolean }): Promise<() => void> { return await jseComm.dispatch({ funcName: 'subscribeToSharedPois', params: { id, cb, unsubscribe }, returnType: true }) } interface MeshObj { sceneID: string, id: string, gltf: string, visible: boolean, position: object, lookat: object, } function mesh (meshObj: MeshObj): void { jseComm.dispatch({ funcName: 'mesh', params: meshObj, returnType: false }) } function cloneMesh (meshObj: MeshObj): void { jseComm.dispatch({ funcName: 'cloneMesh', params: meshObj, returnType: false }) } function destroyMesh (meshObj: MeshObj): void { jseComm.dispatch({ funcName: 'destroyMesh', params: meshObj, returnType: false }) } // TODO: This function isn't used so difficult to guess type, Maybe need to delete. async function getIntersections ({ rays }: { rays: object }): Promise { return await jseComm.dispatch({ funcName: 'getIntersections', params: { rays }, returnType: true }) } async function setUpLights ({ sceneID, lightConfigs, inCameraSpace, ignoreOcclusion }: { sceneID: string, lightConfigs: object, inCameraSpace: boolean, ignoreOcclusion: boolean }): Promise { return await jseComm.dispatch({ funcName: 'setUpLights', params: { sceneID, lightConfigs, inCameraSpace, ignoreOcclusion }, returnType: false }) } async function initScene ({ sceneID, sceneConfig, lightConfigs }: { sceneID: string, sceneConfig: object, lightConfigs: object }): Promise { return await jseComm.dispatch({ funcName: 'initScene', params: { sceneID, sceneConfig, lightConfigs }, returnType: false }) } interface Buttons { buttons: Array<{ id: string, isRegistered: boolean }> } function registerButtons (buttons: Buttons) { jseComm.dispatch({ funcName: 'registerbuttons', params: buttons, returnType: false }) } function setDirty ({ msg }: { msg: string }) { jseComm.dispatch({ funcName: 'setDirty', params: { msg }, returnType: false }) } function setTheme ({ theme }: { theme: string }) { jseComm.dispatch({ funcName: 'setTheme', params: { theme }, returnType: false }) } async function setActivityTitle ({ title }: { title: string }): Promise { return await jseComm.dispatch({ funcName: 'setActivityTitle', params: { title }, returnType: true }) } async function tryOpen ({ activityId }: { activityId: string }): Promise { return await jseComm.dispatch({ funcName: 'tryOpen', params: activityId, returnType: true }) } async function tryClose ({ isExitButtonClicked = false } = {}): Promise { return await jseComm.dispatch({ funcName: 'tryClose', params: { isExitButtonClicked }, returnType: true }) } function openUrl (url: string): void { jseComm.dispatch({ funcName: 'openUrl', params: url, returnType: false }) } function openTab (url: string, callback: () => void): void { jseComm.dispatch({ funcName: 'openTab', params: { url, callback }, returnType: false }) } async function routeNavigation (params: object): Promise { return await jseComm.dispatch({ funcName: 'routeNavigation', params, returnType: true }) } async function findMatchingRegion (params: object): Promise { return await jseComm.dispatch({ funcName: 'findMatchingRegion', params, returnType: true }) } interface GeoFilter { centerX: number, centerZ: number, hDistance: number // Max 2D horizontal distance (m) } interface QuerySemantic { confKey: string, confProperty: string, filter: object, geofilter: GeoFilter, fields: string, size: number, skip: number } interface SemanticObjects { [key: string]: { '$key': string, '@id': string, 'key': string, 'ar-geometry': object } } async function querySemanticObjects ({ confKey, confProperty, filter, geofilter, fields, size, skip }: QuerySemantic): Promise { console.log('confKey: ', confKey) return await jseComm.dispatch({ funcName: 'querySemanticObjects', params: { confKey, confProperty, filter, geofilter, fields, size, skip }, returnType: true }) } function sendArmeMessage ({ packageName, data }: { packageName: string, data: object }): void { console.log('jseApiHelper sendArmeMessage', packageName, data) reportBI({ module: 'jseApiHelper.js', action: 'sendArmeMessage', data: { packageName, data } }) jseComm.dispatch({ funcName: 'sendArmeMessage', params: { packageName, data }, returnType: false }) } function sendNativeMessage ({ data }: { data: {[key: string]: object } }): void { reportBI({ module: 'jseApiHelper.js', action: 'sendNativeMessage', data }) jseComm.dispatch({ funcName: 'sendNativeMessage', params: { data }, returnType: false }) } function closeArmeActivity (callback: () => void): void { if (isLoaded) { console.warn('Please register to closeArmeActivity before calling loaded()') } jseComm.export({ vera: { CloseARMEActivity: callback } }) } function onMessage (callback: () => void): void { if (isLoaded) { console.warn('Please register to onMessage before calling loaded()') } jseComm.export({ vera: { onMessage: callback } }) } function callArmeActivity (callback: () => void): void { if (isLoaded) { console.warn('Please register to callArmeActivity before calling loaded()') } jseComm.export({ vera: { CallARMEActivity: callback } }) } function onBackEvent (callback: () => void): void { if (isLoaded) { console.warn('Please register to onBackEvent before calling loaded()') } jseComm.export({ vera: { backEvent: callback } }) jseComm.dispatch({ funcName: 'registerHasBack', params: {}, returnType: false }) } type SemanticDataForPos = { building: number | undefined, floorIndex: number | undefined, areas: {[area_type: string]: boolean } | undefined } async function getSemanticDataForPos (pos: Array): Promise { return await jseComm.dispatch({ funcName: 'getSemanticDataForPos', params: { pos }, returnType: true }) } function getX (propertyName: string): object { if (reactiveCB[propertyName]) { return reactive[propertyName] } console.error('Try to get', propertyName, 'when it is not registered yet') return {} } function onX (propertyName: string, cb: () => void): () => void { if (!reactiveCB[propertyName] || reactiveCB[propertyName].length === 0) { reactiveCB[propertyName] = [] jseComm.dispatch({ funcName: 'setReactiveProps', params: { props: Object.keys(reactiveCB) }, returnType: false }) } reactiveCB[propertyName].push(cb) return () => { if (!reactiveCB[propertyName]) { return } if (reactiveCB[propertyName].length === 1 && reactiveCB[propertyName][0] === cb) { delete reactiveCB[propertyName] jseComm.dispatch({ funcName: 'setReactiveProps', params: { props: Object.keys(reactiveCB) }, returnType: false }) return } const index = reactiveCB[propertyName].findIndex(cb) if (index >= 0) { reactiveCB[propertyName].splice(index, 1) } } } function onCameraPose (cb: () => void) { return onX('cameraPose', cb) } function getCameraPose (): object { return getX('cameraPose') } function onProjectionMatrix (cb: () => void) { return onX('projectionMatrix', cb) } function getProjectionMatrix (): object { return getX('projectionMatrix') } function onLanguage (cb: () => void) { return onX('language', cb) } function getLanguage (): object { return getX('language') } function onKeyboard (cb: () => void) { return onX('keyboardState', cb) } function getKeyboard (): object { return getX('keyboardState') } function onSemanticLocation (cb: () => void) { return onX('semanticLocation', cb) } function getSemanticLocation (): object { return getX('semanticLocation') } function onSafeArea (cb: () => void) { return onX('safeArea', cb) } function getSafeArea (): object { return getX('safeArea') } function dispatchClickEvent ({ x, y }: { x: number, y: number }): void { jseComm.dispatch({ funcName: 'dispatchClickEvent', params: { x, y }, returnType: false }) } interface ShareData { data: { url: string } } function share (data: { data: ShareData }): void { jseComm.dispatch({ funcName: 'share', params: data, returnType: false }) } function requireTrackingState ({ trackingIsRequired, trackingstate, delay, hint }: { trackingIsRequired?: boolean, trackingstate?: string, delay: number, hint: string }): void { trackingIsRequired = trackingIsRequired ?? trackingstate === 'Tracking' jseComm.dispatch({ funcName: 'requireTrackingState', params: { trackingIsRequired, delay, hint }, returnType: false }) } function hintRegion (data: { detectedRegionId: string, reportedRegionId: string, hintPosition: { x: number, y: number, z: number } }): void { jseComm.dispatch({ funcName: 'hintRegion', params: data, returnType: false }) } function reportBI ({ module, action, data }: { module: string, action: string, data: object }): void { jseComm.dispatch({ funcName: 'reportBI', params: { module, action, data }, returnType: false }) } function vibrate ({ time }: { time: string }): void { jseComm.dispatch({ funcName: 'vibrate', params: { time }, returnType: false }) } function setItem ({ id, value }: { id: string, value: object }): void { jseComm.dispatch({ funcName: 'setInStorage', params: { name: 'store', id, value }, returnType: false }) } async function getItem ({ id }: { id: string }): Promise { const ret = await jseComm.dispatch({ funcName: 'fetchFromStorage', params: { name: 'store', id }, returnType: true }) return ret.data } // Only supported in iOS async function takePhoto (title: string): Promise { return await jseComm.dispatch({ funcName: 'takePhoto', params: { title }, returnType: true }) } // Only supported in iOS async function takeQrCode (title: string): Promise<{ decodedString: string, photo: string, cancelled: boolean }> { return await jseComm.dispatch({ funcName: 'takeQrCode', params: { title }, returnType: true }) } async function identifyUser (title: string, subtitle: string, cancelButton: string): Promise { return await jseComm.dispatch({ funcName: 'identifyUser', params: { title, subtitle, cancel: cancelButton }, returnType: true }) } async function getSOCenter ({ key }: { key: string }): Promise> { return await jseComm.dispatch({ funcName: 'getSOCenter', params: { key }, returnType: true }) } async function getDeviceInfo (): Promise { return await jseComm.dispatch({ funcName: 'getDeviceInfo', params: {}, returnType: true }) } async function setPropertyInAppConfig ({ parent, property, value }: { parent: object, property: string, value: string }): Promise { await jseComm.dispatch({ funcName: 'setPropertyInAppConfig', params: { parent, property, value }, returnType: false }) } async function addElementInAppConfig ({ parent, property }: { parent: object, property: string }): Promise { await jseComm.dispatch({ funcName: 'addElementInAppConfig', params: { parent, property }, returnType: false }) } function activeSO ({ key }: { key: string }): void { jseComm.dispatch({ funcName: 'activeSO', params: { key }, returnType: false }) } function editSO ({ key, parent, property, id }: { key: string, parent: object, property: string, id: string }): void { jseComm.dispatch({ funcName: 'editSO', params: { key, parent, property, id }, returnType: false }) } function abort (): void { jseComm.dispatch({ funcName: 'abort', params: {}, returnType: false }) } function setHeatmap ({ data, config }: { data: any, config: any }): void { jseComm.dispatch({ funcName: 'setHeatmap', params: { data, config }, returnType: false }) } const jseApiHelper = { loaded, getAppConfig, getSiteConfig, isDeeplinkSupported, getNewDeeplink, getSOArProperties, addSharedPoi, removeSharedPoi, subscribeToSharedPois, mesh, cloneMesh, destroyMesh, registerButtons, setDirty, setTheme, tryOpen, setActivityTitle, tryClose, openUrl, openTab, routeNavigation, findMatchingRegion, querySemanticObjects, sendArmeMessage, sendNativeMessage, onMessage, callArmeActivity, closeArmeActivity, onBackEvent, getCameraPose, onCameraPose, getSemanticDataForPos, onSemanticLocation, getSemanticLocation, onSafeArea, getSafeArea, dispatchClickEvent, onProjectionMatrix, getProjectionMatrix, onLanguage, getLanguage, onKeyboard, getKeyboard, share, requireTrackingState, hintRegion, reportBI, getIntersections, setUpLights, initScene, vibrate, setItem, getItem, takePhoto, takeQrCode, identifyUser, getSOCenter, getDeviceInfo, setPropertyInAppConfig, addElementInAppConfig, activeSO, editSO, abort, setHeatmap } export { jseApiHelper as veraApi, /** * @deprecated Use veraApi instead. */ jseApiHelper }