atriusmaps-node-sdk 1.0.0 → 3.2.28

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 (105) hide show
  1. package/README.md +76 -0
  2. package/config/rollup.config.cjs.js +31 -0
  3. package/dist/cjs/_virtual/_empty_module_placeholder.js +5 -0
  4. package/dist/cjs/deploy/nodeEntry.js +15 -0
  5. package/dist/cjs/deploy/prepareSDKConfig.js +9 -0
  6. package/dist/cjs/package.json +1 -0
  7. package/dist/cjs/package.json.js +11 -0
  8. package/dist/cjs/plugins/clientAPI/src/clientAPI.js +9 -0
  9. package/dist/cjs/plugins/dynamicPois/src/dynamicPois.js +33 -0
  10. package/dist/cjs/plugins/poiDataManager/src/poiDataManager.js +36 -0
  11. package/dist/cjs/plugins/sdkServer/src/sdkHeadless.js +31 -0
  12. package/dist/cjs/plugins/sdkServer/src/sdkServer.js +13 -0
  13. package/dist/cjs/plugins/sdkServer/src/util.js +10 -0
  14. package/dist/cjs/plugins/searchService/src/poiSearch.js +28 -0
  15. package/dist/cjs/plugins/searchService/src/searchService.js +37 -0
  16. package/dist/cjs/plugins/searchService/src/searchTypeahead.js +8 -0
  17. package/dist/cjs/plugins/searchService/src/utils.js +13 -0
  18. package/dist/cjs/plugins/venueDataLoader/src/venueDataLoader.js +36 -0
  19. package/dist/cjs/plugins/venueDataLoader/src/venueLoadingUtils.js +34 -0
  20. package/dist/cjs/plugins/wayfinder/src/findRoute.js +30 -0
  21. package/dist/cjs/plugins/wayfinder/src/minPriorityQueue.js +5 -0
  22. package/dist/cjs/plugins/wayfinder/src/navGraph.js +13 -0
  23. package/dist/cjs/plugins/wayfinder/src/navGraphDebug.js +30 -0
  24. package/dist/cjs/plugins/wayfinder/src/segmentBadges.js +5 -0
  25. package/dist/cjs/plugins/wayfinder/src/segmentBuilder.js +32 -0
  26. package/dist/cjs/plugins/wayfinder/src/segmentCategories.js +5 -0
  27. package/dist/cjs/plugins/wayfinder/src/stepBuilder.js +10 -0
  28. package/dist/cjs/plugins/wayfinder/src/wayfinder.js +40 -0
  29. package/dist/cjs/src/app.js +44 -0
  30. package/dist/cjs/src/auth/Auth.js +23 -0
  31. package/dist/cjs/src/configs/postproc-mol-url-parms.js +9 -0
  32. package/dist/cjs/src/configs/postproc-stateTracking.js +31 -0
  33. package/dist/cjs/src/configs/sdkHeadless.json.js +47 -0
  34. package/dist/cjs/src/controller.js +14 -0
  35. package/dist/cjs/src/debugTools.js +30 -0
  36. package/dist/cjs/src/env.js +7 -0
  37. package/dist/cjs/src/extModules/bustle.js +13 -0
  38. package/dist/cjs/src/extModules/flexapi/src/help.js +9 -0
  39. package/dist/cjs/src/extModules/flexapi/src/index.js +13 -0
  40. package/dist/cjs/src/extModules/flexapi/src/validate.js +10 -0
  41. package/dist/cjs/src/extModules/geohasher.js +8 -0
  42. package/dist/cjs/src/extModules/log.js +7 -0
  43. package/dist/cjs/src/historyManager.js +7 -0
  44. package/dist/cjs/src/utils/bounds.js +10 -0
  45. package/dist/cjs/src/utils/buildStructureLookup.js +29 -0
  46. package/dist/cjs/src/utils/configUtils.js +8 -0
  47. package/dist/cjs/src/utils/dom.js +10 -0
  48. package/dist/cjs/src/utils/funcs.js +15 -0
  49. package/dist/cjs/src/utils/geodesy.js +8 -0
  50. package/dist/cjs/src/utils/geom.js +35 -0
  51. package/dist/cjs/src/utils/i18n.js +14 -0
  52. package/dist/cjs/src/utils/observable.js +5 -0
  53. package/dist/cjs/src/utils/rand.js +8 -0
  54. package/lib/_virtual/_empty_module_placeholder.js +1 -0
  55. package/lib/deploy/nodeEntry.js +1 -58
  56. package/lib/deploy/prepareSDKConfig.js +1 -112
  57. package/lib/package.json.js +1 -143
  58. package/lib/plugins/clientAPI/src/clientAPI.js +1 -14
  59. package/lib/plugins/dynamicPois/src/dynamicPois.js +1 -131
  60. package/lib/plugins/poiDataManager/src/poiDataManager.js +1 -207
  61. package/lib/plugins/sdkServer/src/sdkHeadless.js +1 -53
  62. package/lib/plugins/sdkServer/src/sdkServer.js +1 -211
  63. package/lib/plugins/sdkServer/src/util.js +1 -18
  64. package/lib/plugins/searchService/src/poiSearch.js +1 -39
  65. package/lib/plugins/searchService/src/searchService.js +1 -234
  66. package/lib/plugins/searchService/src/searchTypeahead.js +1 -63
  67. package/lib/plugins/searchService/src/utils.js +1 -30
  68. package/lib/plugins/venueDataLoader/src/venueDataLoader.js +1 -465
  69. package/lib/plugins/venueDataLoader/src/venueLoadingUtils.js +1 -84
  70. package/lib/plugins/wayfinder/src/findRoute.js +1 -134
  71. package/lib/plugins/wayfinder/src/minPriorityQueue.js +1 -89
  72. package/lib/plugins/wayfinder/src/navGraph.js +1 -370
  73. package/lib/plugins/wayfinder/src/navGraphDebug.js +1 -95
  74. package/lib/plugins/wayfinder/src/segmentBadges.js +1 -29
  75. package/lib/plugins/wayfinder/src/segmentBuilder.js +1 -241
  76. package/lib/plugins/wayfinder/src/segmentCategories.js +1 -30
  77. package/lib/plugins/wayfinder/src/stepBuilder.js +1 -236
  78. package/lib/plugins/wayfinder/src/wayfinder.js +1 -452
  79. package/lib/src/app.js +1 -150
  80. package/lib/src/auth/Auth.js +1 -35
  81. package/lib/src/configs/postproc-mol-url-parms.js +1 -58
  82. package/lib/src/configs/postproc-stateTracking.js +1 -40
  83. package/lib/src/configs/sdkHeadless.json.js +1 -42
  84. package/lib/src/controller.js +1 -45
  85. package/lib/src/debugTools.js +1 -108
  86. package/lib/src/env.js +1 -17
  87. package/lib/src/extModules/bustle.js +1 -126
  88. package/lib/src/extModules/flexapi/src/help.js +1 -21
  89. package/lib/src/extModules/flexapi/src/index.js +1 -66
  90. package/lib/src/extModules/flexapi/src/validate.js +1 -131
  91. package/lib/src/extModules/geohasher.js +1 -90
  92. package/lib/src/extModules/log.js +1 -70
  93. package/lib/src/historyManager.js +1 -30
  94. package/lib/src/utils/bounds.js +1 -23
  95. package/lib/src/utils/buildStructureLookup.js +1 -17
  96. package/lib/src/utils/configUtils.js +1 -61
  97. package/lib/src/utils/dom.js +1 -46
  98. package/lib/src/utils/funcs.js +1 -50
  99. package/lib/src/utils/geodesy.js +1 -35
  100. package/lib/src/utils/geom.js +1 -141
  101. package/lib/src/utils/i18n.js +1 -70
  102. package/lib/src/utils/observable.js +1 -76
  103. package/lib/src/utils/rand.js +1 -82
  104. package/package.json +23 -6
  105. package/lib/_virtual/_empty_module_placeholder +0 -3
@@ -1,465 +1 @@
1
- import * as R from 'ramda';
2
- import Zousan from 'zousan';
3
- import Auth from '../../../src/auth/Auth.js';
4
- import { delay } from '../../../src/utils/funcs.js';
5
- import { getVenueDataFromUrls, buildStructures, createFetchJson, createFetchText } from './venueLoadingUtils.js';
6
-
7
- const USE_AUTH_WHEN_NOT_PROD_STAGE = false; // turning this off for now (per Jessica request)
8
-
9
- async function create (app, config) {
10
- const log = app.log.sublog('venueDataLoader');
11
- let venueDataLoaded = new Zousan();
12
- let mapDataLoaded = new Zousan();
13
-
14
- const getDefaultStructureId = venueData =>
15
- venueData.defaultStructureId ||
16
- R.path(['structureOrder', 0], venueData) ||
17
- R.path(['selectorOrder', 0], venueData) ||
18
- R.pipe(R.prop('structures'), Object.values, R.path([0, 'id']))(venueData);
19
-
20
- const mergeWithProp = (prop, toAdd, o) => R.over(R.lensProp(prop), old => R.mergeRight(old || {}, toAdd), o);
21
-
22
- // the following function employs a bit of silliness because immediately after
23
- // a federated login, the call to getToken() doesn't always work right away.
24
- // Sometimes it takes 500ms, sometimes 1000ms.
25
- // So, this approach allows it to take up to 3 seconds - but if it notices sooner,
26
- // it exits out.
27
- const LOOP_TRIES = 6; const DELAY_PER_LOOP = 500;
28
- async function getVenueDataAuthToken (authConfig) {
29
- const auth = await Auth(authConfig, app);
30
-
31
- let token = null; let loopTry = 0;
32
- while (!token && loopTry < LOOP_TRIES) {
33
- token = await auth.getToken();
34
- loopTry++;
35
- if (!token)
36
- await delay(DELAY_PER_LOOP)();
37
- }
38
-
39
- if (token) {
40
- app.bus.send('login/userLoggedIn', { token: token });
41
- app.bus.on('app/logout', auth.logout);
42
- return token
43
- }
44
-
45
- return app.bus.get('login/showLogin', { auth: auth }) // should return a token
46
- }
47
-
48
- const getLanguageObject = (lang) => {
49
- const result = config.availableLanguages.find(el => el.langCode === lang);
50
- if (!result) {
51
- return { langCode: lang, assetSuffix: '' }
52
- }
53
- return result
54
- };
55
-
56
- async function loadVenueData (vConfig) {
57
- // For all non-production stages, require SSO (if no assetStage defined we default to 'prod')
58
- if (vConfig.assetStage && vConfig.assetStage !== 'prod' && location.hostname !== 'localhost' && USE_AUTH_WHEN_NOT_PROD_STAGE)
59
- vConfig.auth = {
60
- type: 'cognito',
61
- config: {
62
- userPoolWebClientId: '484dghfpojlldauo956d84jtrj'
63
- }
64
- };
65
-
66
- const authToken = vConfig.auth
67
- ? await getVenueDataAuthToken(vConfig.auth)
68
- : null;
69
-
70
- const fetchJson = createFetchJson(authToken);
71
- const fetchText = createFetchText(authToken);
72
-
73
- const venueData = await getVenueDataFromUrls(vConfig, fetchJson);
74
-
75
- const { accountId, venueId } = vConfig;
76
-
77
- venueData.assetStage = vConfig.assetStage;
78
-
79
- venueData.defaultOrdinal = venueData.defaultOrdinal || getDefaultOrdinal(venueData);
80
- venueData.structures = buildStructures(venueData);
81
- const currentLang = app.i18n().language;
82
- const langObj = getLanguageObject(currentLang);
83
- venueData.bareVenueId = venueId.slice(0, venueId.length - langObj.assetSuffix.length);
84
- venueData.getTranslatedContentPath = contentType => `https://content.locuslabs.com/${venueData.category}/${contentType}/${venueId}/${accountId}`;
85
- venueData.fetchJson = fetchJson;
86
- venueData.fetchText = fetchText;
87
- log.info('venueData ', venueData, langObj, currentLang);
88
- if (app.config.debug && app.env.isBrowser)
89
- window._venueData = venueData;
90
- app.bus.send('venueData/venueDataLoaded', { venueData });
91
-
92
- venueDataLoaded.resolve(venueData);
93
- return venueDataLoaded
94
- }
95
-
96
- function getDefaultOrdinal (venueData) {
97
- const defaultStructureId = getDefaultStructureId(venueData);
98
- const defaultStructure = Object.values(venueData.structures).find(R.propEq('id', defaultStructureId));
99
- return defaultStructure.levels[defaultStructure.defaultLevelId].ordinal
100
- }
101
-
102
- function notifyState (venueData) {
103
- const state = { id: 'venueDataLoader' };
104
- if (venueData.id !== config.venueId)
105
- state.vid = venueData.id;
106
- const defaultLang = app.config.defaultLanguage || 'en';
107
- if (app.i18n().language !== defaultLang)
108
- state.lang = app.i18n().language;
109
- if (venueData.assetStage !== 'prod')
110
- state.stage = venueData.assetStage;
111
- app.bus.send('deepLinking/notifyState', state);
112
- return venueData
113
- }
114
-
115
- app.bus.on('debugTools/fileDrop', async ({ file, content }) => {
116
- if (file.type === 'application/json') {
117
- const jsonOb = JSON.parse(content);
118
- if (jsonOb.basemap && jsonOb['basemap.venue'])
119
- return replaceTheme(JSON.parse(content)) // looks like a theme!
120
- if (jsonOb.metadata && jsonOb.metadata['mapbox:type'])
121
- return replaceStyle(content) // looks like a style!
122
- }
123
- });
124
-
125
- // Returns true if category c1 is within category c2.
126
- // "within" here means they either are the same category
127
- // or c2 is a subcategory of c1
128
- // i.e. withinCategory("eat", "eat") = true
129
- // withinCategory("eat.coffee", "eat") = true
130
- // withinCategory("eat", "eat.coffee") = false
131
- const withinCategory = (c1, c2) => c1 === c2 || c1.indexOf(c2 + '.') === 0;
132
-
133
- function poiMapNameXForm (poi) {
134
- let name = poi.name;
135
- if (!config.poiMapNameXForm)
136
- return name // no transforms for me today, thanks
137
- Object.keys(config.poiMapNameXForm)
138
- .filter(c2 => withinCategory(poi.category, c2))
139
- .forEach(c2 => {
140
- const xforms = config.poiMapNameXForm[c2]; // an array of xforms
141
- xforms.forEach(xform => (name = name.replace(new RegExp(xform.replace), xform.with)));
142
- });
143
- return name
144
- }
145
-
146
- /*
147
- This function replaces POI labels with the poi.mapLabel (if it exists).
148
- If it does not exist and the config.copyPOINamesToMap is not explicitly set
149
- to `false` - then we copy the name from poi.name (and then put it through a
150
- set of transformations)
151
- */
152
- async function copyPOINames (mapFeatures) {
153
- const newMapFeatures = { ...mapFeatures };
154
- const pois = await app.bus.get('poi/getAll');
155
-
156
- Object.values(newMapFeatures)
157
- .forEach(layerArray =>
158
- layerArray
159
- .filter(f => f.properties.aiLayer === 'poi' && f.geometry.type === 'Point')
160
- .forEach(f => {
161
- const poi = pois[f.properties.id];
162
- if (!poi)
163
- log.warn(`Unknown poi in style: ${f.properties.id}`);
164
- else {
165
- if (poi.mapLabel)
166
- f.properties.text = poi.mapLabel;
167
- else
168
- if (config.copyPOINamesToMap !== false)
169
- f.properties.text = poiMapNameXForm(poi);
170
- }
171
- }));
172
-
173
- return newMapFeatures
174
- }
175
-
176
- // pass in theme object (parsed from theme file)
177
- function replaceTheme (mapThemeSource) {
178
- app.bus.send('map/replaceTheme', { theme: mapThemeSource });
179
- }
180
-
181
- function replaceStyle (mapStyleSource) {
182
- app.bus.send('map/replaceStyle', { styleSrc: mapStyleSource });
183
- }
184
-
185
- /**
186
- * Creates list of source ids from all floor ids and venue id and fetches GeoJSON features for each id.
187
- * Returns dictionary of source id to list of GeoJson features
188
- * @returns {Promise<Object<string, Array.<GeoJson>>>}
189
- */
190
- async function getMapFeatures (venueData) {
191
- return R.pipe(
192
- R.prop('structures'),
193
- R.map(R.prop('levels')),
194
- R.chain(R.keys),
195
- // Generate list of level IDs plus the venue ID to fetch feature JSON for each
196
- R.prepend(venueData.id),
197
- // eslint-disable-next-line no-template-curly-in-string
198
- R.map(geoJsonId => venueData.files.geoJson.replace('${geoJsonId}', geoJsonId)),
199
- R.map(venueData.fetchJson),
200
- R.map(R.andThen(featureJSON =>
201
- [featureJSON.id, enrichFeaturesForLevel(featureJSON.id, featureJSON.features, venueData.id, venueData.structures)])),
202
- promises => Promise.all(promises),
203
- R.andThen(R.fromPairs)
204
- )(venueData)
205
- }
206
-
207
- const enrichFeaturesForLevel = (levelId, features, venueId, structures) => {
208
- const structureId = levelId.replace(/-[^-]*$/, '');
209
- const ordinalId = structureId === venueId
210
- ? 'landscape-background'
211
- : `ordinal: ${structures.find(R.hasPath(['levels', levelId])).levels[levelId].ordinal}`;
212
- const enrichFeature = (feature) => {
213
- feature = mergeWithProp('properties', ({ venueId, structureId, ordinalId, levelId }), feature);
214
- feature = R.assoc('id', feature.properties.subid, feature);
215
- return feature
216
- };
217
- return features.map(enrichFeature)
218
- };
219
-
220
- /**
221
- * Fetches map style, map theme, map GeoJson feature sources.
222
- * Transforms data to convenient format and sends an event venueData/mapDataLoaded with map data.
223
- */
224
- app.bus.on('venueData/loadMap', async () => {
225
- venueDataLoaded.then(async venueData => {
226
- const mapStyleSource = await venueData.fetchText(venueData.files.style);
227
- const mapTheme = await venueData.fetchJson(venueData.files.theme);
228
- const badgesSpriteUrl = venueData.files.spritesheet;
229
- const mapGlyphsUrl = venueData.files.glyphs;
230
- const { id, bounds, structures, venueCenter, venueRadius, defaultOrdinal } = venueData;
231
- const mapFeatures = await getMapFeatures(venueData).then(copyPOINames);
232
- const venueBounds = {
233
- n: bounds.ne.lat,
234
- s: bounds.sw.lat,
235
- e: bounds.ne.lng,
236
- w: bounds.sw.lng
237
- };
238
- const mapData = {
239
- mapFeatures,
240
- mapStyleSource,
241
- mapTheme,
242
- badgesSpriteUrl,
243
- mapGlyphsUrl,
244
- structures,
245
- defaultOrdinal,
246
- venueBounds,
247
- venueId: id,
248
- venueCenter,
249
- venueRadius,
250
- accountId: config.accountId,
251
- secure: config.auth !== undefined
252
- };
253
- mapDataLoaded.resolve(mapData);
254
- app.bus.send('venueData/mapDataLoaded', mapData);
255
- });
256
- });
257
-
258
- // accept when shouldDisplay is null or undefined or true
259
- const shouldDisplayPredicate = building => building.shouldDisplay == null || building.shouldDisplay;
260
-
261
- // todo check if all async events are still needed (events that sends a new event as result, like 'venueData/buildingSelectorDataLoaded')
262
- app.bus.on('venueData/loadBuildingSelectorData', () => {
263
- return venueDataLoaded.then(async venueData => {
264
- // displayable buildings with levels list ordered by ordinal desc.
265
- const buildings = venueData.structures
266
- .filter(shouldDisplayPredicate)
267
- .map(R.evolve({ // creates copy of structure with modified levels
268
- levels: R.pipe(R.values, R.sortWith([R.descend(R.prop('ordinal'))]))
269
- }));
270
-
271
- // todo order buildings using structureOrder and selectorOrder
272
- // currently structures ordering is duplicated in level selectors handlers
273
- // then we can remove structureOrder and selectorOrder from result
274
- const result = {
275
- buildings,
276
- structureOrder: venueData.structureOrder,
277
- selectorOrder: venueData.selectorOrder
278
- };
279
- app.bus.send('venueData/buildingSelectorDataLoaded', result);
280
- return result
281
- })
282
- });
283
-
284
- app.bus.on('venueData/loadNavGraph', async () => {
285
- return venueDataLoaded.then(async venueData => {
286
- const navGraphData = await venueData.fetchJson(venueData.files.nav);
287
- app.bus.send('venueData/navGraphLoaded', { navGraphData, structures: venueData.structures });
288
- })
289
- });
290
-
291
- app.bus.on('venueData/loadPoiData', async () => {
292
- return venueDataLoaded.then(async venueData => {
293
- const poisUrl = config.useOldDataModel
294
- ? venueData.files.poisOld || venueData.files.pois
295
- : venueData.files.pois || venueData.files.poisOld;
296
- const pois = await venueData.fetchJson(poisUrl);
297
- app.bus.send('venueData/poiDataLoaded', { pois, structures: venueData.structures });
298
- })
299
- });
300
-
301
- app.bus.on('venueData/getVenueCenter', async () => venueDataLoaded.then(async venueData => (
302
- { lat: venueData.venueCenter[0], lng: venueData.venueCenter[1], ordinal: 0 })));
303
-
304
- app.bus.on('venueData/getContentUrl', ({ type, name = '' }) =>
305
- venueDataLoaded.then(venueData => venueData.files[type] + name));
306
-
307
- app.bus.on('venueData/getFloorIdToNameMap', () => venueDataLoaded.then(R.pipe(
308
- R.prop('structures'),
309
- R.map(R.prop('levels')), // get levels for each structure
310
- R.chain(R.values), // flatten structures levels into single array
311
- R.map(R.props(['id', 'name'])), // create pairs [id, name]
312
- R.fromPairs // create map of 'id' to 'name'
313
- )));
314
-
315
- app.bus.on('venueData/getFloorIdName', ({ floorId }) => {
316
- return venueDataLoaded.then(async venueData => {
317
- const structure = R.pipe(R.values, R.find(R.hasPath(['levels', floorId])))(venueData.structures);
318
- if (!structure) return null
319
- return {
320
- structureId: structure.id,
321
- structureName: structure.name,
322
- floorName: structure.levels[floorId].name
323
- }
324
- })
325
- });
326
-
327
- const getVenueDataProp = (propName, defaultValue) => () => venueDataLoaded.then(R.pipe(R.prop(propName), R.defaultTo(defaultValue)));
328
-
329
- app.bus.on('venueData/getVenueData', () => venueDataLoaded);
330
-
331
- app.bus.on('venueData/getVenueName', getVenueDataProp('name'));
332
-
333
- app.bus.on('venueData/getVenueCategory', getVenueDataProp('category'));
334
-
335
- app.bus.on('venueData/getVenueTimezone', getVenueDataProp('tz'));
336
- app.bus.on('venueData/getAccountId', () => config.accountId);
337
- app.bus.on('venueData/getVenueId', getVenueDataProp('id'));
338
-
339
- app.bus.on('venueData/getPositioningSupported', getVenueDataProp('positioningSupported'));
340
- app.bus.on('venueData/getStructures', getVenueDataProp('structures'));
341
-
342
- app.bus.on('venueData/loadNewVenue', async ({ venueId, accountId, assetStage = config.assetStage }) => {
343
- venueDataLoaded.reject(new Error('loadNewVenue called - previous loading ignored'));
344
- mapDataLoaded.reject(new Error('loadNewVenue called - previous loading ignored'));
345
- venueDataLoaded = new Zousan();
346
- mapDataLoaded = new Zousan();
347
- loadVenueData({ ...config, venueId, accountId, assetStage })
348
- .then(notifyState);
349
- });
350
-
351
- app.bus.on('venueData/changeVenueLanguage', async ({ lang }) => {
352
- return venueDataLoaded.then(async venueData => {
353
- const langObj = getLanguageObject(lang);
354
- const newVenueId = `${venueData.bareVenueId}${langObj.assetSuffix}`;
355
- app.bus.send('venueData/loadNewVenue', { accountId: config.accountId, venueId: newVenueId });
356
- })
357
- });
358
-
359
- // returns a full URL to an image hosted on img.locuslabs.com, size has to be a string of format ${width}x${height}
360
- app.bus.on('venueData/getPoiImageUrl', ({ imageName, size }) => {
361
- return `https://img.locuslabs.com/resize/${config.accountId}/${size}cc/poi/${imageName}`
362
- });
363
-
364
- // This is an utility function that returns a unique ID used to distinguish certain, installation/deployment specific parts
365
- // for now it uses venueId and accountId and is used to fix collision when storing data in localStorage
366
- app.bus.on('venueData/getDistributionId', () => {
367
- return venueDataLoaded.then(venueData => {
368
- return `${venueData.bareVenueId}-${config.accountId}`
369
- })
370
- });
371
-
372
- app.bus.on('venueData/getCustomKeywords', () =>
373
- venueDataLoaded.then(venueData => {
374
- const searchUrl = config.useOldDataModel
375
- ? venueData.files.searchOld || venueData.files.search
376
- : venueData.files.search;
377
- return venueData.fetchJson(searchUrl)
378
- }));
379
-
380
- app.bus.on('venueData/isGrabEnabled', getVenueDataProp('enableGrab'));
381
-
382
- app.bus.on('venueData/getGrabPoiIds', getVenueDataProp('grabPoiIds', []));
383
-
384
- app.bus.on('venueData/getAssetsTimestamp', getVenueDataProp('version'));
385
-
386
- app.bus.on('venueData/getTranslatedFloorId', async ({ floorId }) => {
387
- return venueDataLoaded.then(venueData => {
388
- const currentLang = app.i18n().language;
389
- const langObj = getLanguageObject(currentLang);
390
- return `${venueData.bareVenueId}${langObj.assetSuffix}-${floorId.split('-').slice(1).join('-')}`
391
- })
392
- });
393
-
394
- /**
395
- * Returns object with queue types (security and immigration lanes) that are present in the venue defined in venue data.
396
- * Also adds image id for lanes with images.
397
- *
398
- * @typedef QueueType
399
- * @property {boolean} default
400
- * @property {string} defaultText
401
- * @property {string} id
402
- * @property {string} imageId
403
- *
404
- * @typedef QueueTypes
405
- * @property {QueueType[]} SecurityLane - list of security categories
406
- * @property {QueueType[]} ImmigrationLane - list of immigration categories
407
- *
408
- * @return {QueueTypes} queueTypes
409
- */
410
- app.bus.on('venueData/getQueueTypes', () => {
411
- return venueDataLoaded.then(venueData => {
412
- const lanesWithImages = ['tsapre', 'clear', 'globalEntry'];
413
- if (venueData.queueTypes) {
414
- return venueData.queueTypes.reduce((obj, category) => {
415
- const { id, subtypes } = category;
416
- const typesWithImages = subtypes.map(type => {
417
- const imageId = lanesWithImages.includes(type.id) && `security-logo-${type.id.toLowerCase()}`;
418
- return { ...type, imageId }
419
- });
420
- obj[id] = typesWithImages;
421
- return obj
422
- }, {})
423
- } else return {}
424
- })
425
- });
426
-
427
- const runTest = async ({ testRoutine, reset = false, venueData = null }) => {
428
- if (reset || venueData) {
429
- venueDataLoaded = new Zousan();
430
- mapDataLoaded = new Zousan();
431
- }
432
- if (venueData)
433
- venueDataLoaded = Zousan.resolve(venueData);
434
-
435
- await testRoutine();
436
-
437
- let venueDataObj, mapDataObj;
438
- if (venueDataLoaded.v)
439
- venueDataObj = await venueDataLoaded;
440
- if (mapDataLoaded.v)
441
- mapDataObj = await mapDataLoaded;
442
- return { venueDataObj, mapDataObj }
443
- };
444
-
445
- const init = async () => {
446
- const deepLinkProps = config.deepLinkProps || {};
447
- const venueId = deepLinkProps.vid || config.venueId;
448
- const assetStage = config.useDynamicUrlParams && deepLinkProps.stage
449
- ? deepLinkProps.stage
450
- : config.assetStage;
451
- const accountId = assetStage === 'alpha' ? 'A1VPTJKREFJWX5' : config.accountId;
452
- loadVenueData({ ...config, venueId, accountId, assetStage })
453
- .then(notifyState);
454
- };
455
-
456
- return {
457
- init,
458
- runTest,
459
- internal: {
460
- getDefaultStructureId
461
- }
462
- }
463
- }
464
-
465
- export { create };
1
+ import*as e from"ramda";import a from"zousan";import t from"../../../src/auth/Auth.js";import{delay as n}from"../../../src/utils/funcs.js";import{getVenueDataFromUrls as s,buildStructures as u,createFetchJson as o,createFetchText as r}from"./venueLoadingUtils.js";async function i(i,l){const d=i.log.sublog("venueDataLoader");let c=new a,p=new a;const g=a=>a.defaultStructureId||e.path(["structureOrder",0],a)||e.path(["selectorOrder",0],a)||e.pipe(e.prop("structures"),Object.values,e.path([0,"id"]))(a);const v=e=>{const a=l.availableLanguages.find((a=>a.langCode===e));return a||{langCode:e,assetSuffix:""}};async function f(a){a.assetStage&&"prod"!==a.assetStage&&location.hostname;const l=a.auth?await async function(e){const a=await t(e,i);let s=null,u=0;for(;!s&&u<6;)s=await a.getToken(),u++,s||await n(500)();return s?(i.bus.send("login/userLoggedIn",{token:s}),i.bus.on("app/logout",a.logout),s):i.bus.get("login/showLogin",{auth:a})}(a.auth):null,p=o(l),f=r(l),b=await s(a,p),{accountId:m,venueId:h}=a;b.assetStage=a.assetStage,b.defaultOrdinal=b.defaultOrdinal||function(a){const t=g(a),n=Object.values(a.structures).find(e.propEq("id",t));return n.levels[n.defaultLevelId].ordinal}(b),b.structures=u(b);const y=i.i18n().language,D=v(y);return b.bareVenueId=h.slice(0,h.length-D.assetSuffix.length),b.getTranslatedContentPath=e=>`https://content.locuslabs.com/${b.category}/${e}/${h}/${m}`,b.fetchJson=p,b.fetchText=f,d.info("venueData ",b,D,y),i.config.debug&&i.env.isBrowser&&(window._venueData=b),b.queueTypes&&(b.securityQueueTypes=(()=>{const e=b.queueTypes.find((e=>"SecurityLane"===e.id));return e?e.subtypes.map((e=>e.id)):[]})()),i.bus.send("venueData/venueDataLoaded",{venueData:b}),c.resolve(b),c}function b(e){const a={id:"venueDataLoader"};e.id!==l.venueId&&(a.vid=e.id);const t=i.config.defaultLanguage||"en";return i.i18n().language!==t&&(a.lang=i.i18n().language),"prod"!==e.assetStage&&(a.stage=e.assetStage),i.bus.send("deepLinking/notifyState",a),e}i.bus.on("debugTools/fileDrop",(async({file:e,content:a})=>{if("application/json"===e.type){const e=JSON.parse(a);if(e.basemap&&e["basemap.venue"])return n=JSON.parse(a),void i.bus.send("map/replaceTheme",{theme:n});if(e.metadata&&e.metadata["mapbox:type"])return t=a,void i.bus.send("map/replaceStyle",{styleSrc:t})}var t,n}));async function m(e){const a={...e},t=await i.bus.get("poi/getAll");return Object.values(a).forEach((e=>e.filter((e=>"poi"===e.properties.aiLayer&&"Point"===e.geometry.type)).forEach((e=>{const a=t[e.properties.id];a?a.mapLabel?e.properties.text=a.mapLabel:!1!==l.copyPOINamesToMap&&(e.properties.text=function(e){let a=e.name;return l.poiMapNameXForm?(Object.keys(l.poiMapNameXForm).filter((a=>((e,a)=>e===a||0===e.indexOf(a+"."))(e.category,a))).forEach((e=>{l.poiMapNameXForm[e].forEach((e=>a=a.replace(new RegExp(e.replace),e.with)))})),a):a}(a)):d.warn(`Unknown poi in style: ${e.properties.id}`)})))),a}const h=(a,t,n,s)=>{const u=a.replace(/-[^-]*$/,""),o=u===n?"landscape-background":`ordinal: ${s.find(e.hasPath(["levels",a])).levels[a].ordinal}`;return t.map((t=>{var s,r,i;return s="properties",r={venueId:n,structureId:u,ordinalId:o,levelId:a},i=t,t=e.over(e.lensProp(s),(a=>e.mergeRight(a||{},r)),i),t=e.assoc("id",t.properties.subid,t)}))};i.bus.on("venueData/loadMap",(async()=>{c.then((async a=>{const t=await a.fetchText(a.files.style),n=await a.fetchJson(a.files.theme),s=a.files.spritesheet,u=a.files.glyphs,{id:o,bounds:r,structures:d,venueCenter:c,venueRadius:g,defaultOrdinal:v}=a,f={mapFeatures:await async function(a){return e.pipe(e.prop("structures"),e.map(e.prop("levels")),e.chain(e.keys),e.prepend(a.id),e.map((e=>a.files.geoJson.replace("${geoJsonId}",e))),e.map(a.fetchJson),e.map(e.andThen((e=>[e.id,h(e.id,e.features,a.id,a.structures)]))),(e=>Promise.all(e)),e.andThen(e.fromPairs))(a)}(a).then(m),mapStyleSource:t,mapTheme:n,badgesSpriteUrl:s,mapGlyphsUrl:u,structures:d,defaultOrdinal:v,venueBounds:{n:r.ne.lat,s:r.sw.lat,e:r.ne.lng,w:r.sw.lng},venueId:o,venueCenter:c,venueRadius:g,accountId:l.accountId,secure:void 0!==l.auth};p.resolve(f),i.bus.send("venueData/mapDataLoaded",f)}))}));const y=e=>null==e.shouldDisplay||e.shouldDisplay;i.bus.on("venueData/loadBuildingSelectorData",(()=>c.then((async a=>{const t={buildings:a.structures.filter(y).map(e.evolve({levels:e.pipe(e.values,e.sortWith([e.descend(e.prop("ordinal"))]))})),structureOrder:a.structureOrder,selectorOrder:a.selectorOrder};return i.bus.send("venueData/buildingSelectorDataLoaded",t),t})))),i.bus.on("venueData/loadNavGraph",(async()=>c.then((async e=>{const a=await e.fetchJson(e.files.nav);i.bus.send("venueData/navGraphLoaded",{navGraphData:a,structures:e.structures})})))),i.bus.on("venueData/loadPoiData",(async()=>c.then((async e=>{const a=l.useOldDataModel?e.files.poisOld||e.files.pois:e.files.pois||e.files.poisOld,t=await e.fetchJson(a);i.bus.send("venueData/poiDataLoaded",{pois:t,structures:e.structures})})))),i.bus.on("venueData/getVenueCenter",(async()=>c.then((async e=>({lat:e.venueCenter[0],lng:e.venueCenter[1],ordinal:0}))))),i.bus.on("venueData/getContentUrl",(({type:e,name:a=""})=>c.then((t=>t.files[e]+a)))),i.bus.on("venueData/getFloorIdToNameMap",(()=>c.then(e.pipe(e.prop("structures"),e.map(e.prop("levels")),e.chain(e.values),e.map(e.props(["id","name"])),e.fromPairs)))),i.bus.on("venueData/getFloorIdName",(({floorId:a})=>c.then((async t=>{const n=e.pipe(e.values,e.find(e.hasPath(["levels",a])))(t.structures);return n?{structureId:n.id,structureName:n.name,floorName:n.levels[a].name}:null}))));const D=(a,t)=>()=>c.then(e.pipe(e.prop(a),e.defaultTo(t)));i.bus.on("venueData/getVenueData",(()=>c)),i.bus.on("venueData/getVenueName",D("name")),i.bus.on("venueData/getVenueCategory",D("category")),i.bus.on("venueData/getVenueTimezone",D("tz")),i.bus.on("venueData/getAccountId",(()=>l.accountId)),i.bus.on("venueData/getVenueId",D("id")),i.bus.on("venueData/getPositioningSupported",D("positioningSupported")),i.bus.on("venueData/getStructures",D("structures")),i.bus.on("venueData/loadNewVenue",(async({venueId:e,accountId:t,assetStage:n=l.assetStage})=>{c.reject(new Error("loadNewVenue called - previous loading ignored")),p.reject(new Error("loadNewVenue called - previous loading ignored")),c=new a,p=new a,f({...l,venueId:e,accountId:t,assetStage:n}).then(b)})),i.bus.on("venueData/changeVenueLanguage",(async({lang:e})=>c.then((async a=>{const t=v(e),n=`${a.bareVenueId}${t.assetSuffix}`;i.bus.send("venueData/loadNewVenue",{accountId:l.accountId,venueId:n})})))),i.bus.on("venueData/getPoiImageUrl",(({imageName:e,size:a})=>`https://img.locuslabs.com/resize/${l.accountId}/${a}cc/poi/${e}`)),i.bus.on("venueData/getDistributionId",(()=>c.then((e=>`${e.bareVenueId}-${l.accountId}`)))),i.bus.on("venueData/getCustomKeywords",(()=>c.then((e=>{const a=l.useOldDataModel&&e.files.searchOld||e.files.search;return e.fetchJson(a)})))),i.bus.on("venueData/isGrabEnabled",D("enableGrab")),i.bus.on("venueData/getGrabPoiIds",D("grabPoiIds",[])),i.bus.on("venueData/getAssetsTimestamp",D("version")),i.bus.on("venueData/getTranslatedFloorId",(async({floorId:e})=>c.then((a=>{const t=i.i18n().language,n=v(t);return`${a.bareVenueId}${n.assetSuffix}-${e.split("-").slice(1).join("-")}`})))),i.bus.on("venueData/getQueueTypes",(()=>c.then((e=>{const a=["tsapre","clear","globalEntry"];return e.queueTypes?e.queueTypes.reduce(((e,t)=>{const{id:n,subtypes:s}=t,u=s.map((e=>{const t=a.includes(e.id)&&`security-logo-${e.id.toLowerCase()}`;return{...e,imageId:t}}));return e[n]=u,e}),{}):{}}))));return{init:async()=>{const e=l.deepLinkProps||{},a=e.vid||l.venueId,t=l.useDynamicUrlParams&&e.stage?e.stage:l.assetStage,n="alpha"===t?"A1VPTJKREFJWX5":l.accountId;f({...l,venueId:a,accountId:n,assetStage:t}).then(b)},runTest:async({testRoutine:e,reset:t=!1,venueData:n=null})=>{let s,u;return(t||n)&&(c=new a,p=new a),n&&(c=a.resolve(n)),await e(),c.v&&(s=await c),p.v&&(u=await p),{venueDataObj:s,mapDataObj:u}},internal:{getDefaultStructureId:g}}}export{i as create};
@@ -1,84 +1 @@
1
- import * as R from 'ramda';
2
- import { findBoundsOfCoordinates } from '../../../src/utils/bounds.js';
3
-
4
- const fetchURL = async (token, url) => {
5
- if (token) {
6
- return fetch(url, {
7
- headers: {
8
- Authorization: token
9
- }
10
- })
11
- } else
12
- return fetch(url)
13
- };
14
-
15
- const createFetchJson = (token) => url => fetchURL(token, url).then(response => response.json());
16
- const createFetchText = (token) => url => fetchURL(token, url).then(response => response.text());
17
-
18
- const baseContentUrl = (contentStage) => `https://api.content.locuslabs.com/${contentStage}`;
19
-
20
- const remapContentUrl = (url, category, contentStage, accountId, venueId, key) => {
21
- if (key === 'theme' || key === 'style') {
22
- return `${baseContentUrl(contentStage)}/${category}/${key}/${venueId}/${accountId}/${key}.json`
23
- }
24
- return url.replace(/https:\/\/content.locuslabs.com/gi, baseContentUrl(contentStage))
25
- };
26
-
27
- const remapEachURLForContentStage = (category, files, contentStage, accountId, venueId) =>
28
- R.mapObjIndexed((file, key) => remapContentUrl(file, category, contentStage, accountId, venueId, key), files);
29
-
30
- const getContentStage = (vconfig) => {
31
- const stage = vconfig.deepLinkProps ? vconfig.deepLinkProps.contentStage : null;
32
- return stage === 'alpha' || stage === 'beta' || stage === 'prod' ? stage : null
33
- };
34
-
35
- const getVenueDataFromUrls = async (vconfig, fetchJson) => {
36
- const stages = {
37
- alpha: 'alpha-a.locuslabs.com',
38
- beta: 'beta-a.locuslabs.com',
39
- gamma: 'gamma-a.locuslabs.com',
40
- prod: 'a.locuslabs.com'
41
- };
42
- const { assetStage, venueId, accountId, formatVersion } = vconfig;
43
- const stageUrl = stages[assetStage] || stages.prod;
44
- const accountUrl = `https://${stageUrl}/accounts/${accountId}`;
45
- const assetFormat = formatVersion || 'v5';
46
- const venueList = await fetchJson(`${accountUrl}/${assetFormat}.json`);
47
- const files = venueList[venueId].files; // mapping of asset "types" (spritesheet, style, badges, etc) to their URL
48
-
49
- const fetchedData = await fetchJson(files.venueData);
50
- const venueData = fetchedData[venueId];
51
- venueData.venueList = venueList;
52
- const contentStage = getContentStage(vconfig);
53
- venueData.files = contentStage // if a contentStage is defined, remap content URLs (see https://locuslabs.gitlab.io/webengine/webengine/contentStaging.html)
54
- ? remapEachURLForContentStage(venueData.category, files, contentStage, accountId, venueId)
55
- : files;
56
-
57
- return venueData
58
- };
59
-
60
- const buildStructures = (venueData) => {
61
- const { structureOrder, structures } = venueData;
62
- return structureOrder.map(structureId => {
63
- const structure = structures[structureId];
64
- // Was going to use this for selecting floors - but it seems floor bounds are incorrect? (was testing LAX/lax-msc-2 for example)
65
- // Object.values(structure.levels).forEach(level => (level.bounds = findBoundsOfCoordinates(level.boundsPolygon)))
66
- const bounds = findBoundsOfCoordinates(structure.boundsPolygon);
67
- return { ...structure, bounds }
68
- })
69
- };
70
-
71
- // If config.useDynamicUrlParams is true, allow changing even security-related parameters in
72
- // the URL - else, only allow the changing of "end-user-changable" parameters, such as vid
73
- // export function updateConfigWithUrlParams (config) {
74
- // const dlp = config.deepLinkProps
75
- // if (dlp) {
76
- // const venueId = dlp.vid ? dlp.vid : config.venueId
77
- // const assetStage = config.useDynamicUrlParams && dlp.stage ? dlp.stage : config.assetStage
78
- // const accountId = assetStage === 'alpha' ? 'A1VPTJKREFJWX5' : config.accountId
79
- // return { ...config, venueId, assetStage, accountId }
80
- // }
81
- // return config
82
- // }
83
-
84
- export { buildStructures, createFetchJson, createFetchText, getVenueDataFromUrls };
1
+ import*as t from"ramda";import{findBoundsOfCoordinates as a}from"../../../src/utils/bounds.js";import{global as e}from"../../../src/utils/configUtils.js";const s=async(t,a)=>t?fetch(a,{headers:{Authorization:t}}):fetch(a),o=t=>a=>s(t,a).then((t=>t.json())),c=t=>a=>s(t,a).then((t=>t.text())),n=t=>`https://api.content.locuslabs.com/${t}`,r=(a,e,s,o,c)=>t.mapObjIndexed(((t,e)=>((t,a,e,s,o,c)=>"theme"===c||"style"===c?`${n(e)}/${a}/${c}/${o}/${s}/${c}.json`:t.replace(/https:\/\/content.locuslabs.com/gi,n(e)))(t,a,s,o,c,e)),e),u=async(t,a)=>{const s={alpha:"alpha-a.locuslabs.com",beta:"beta-a.locuslabs.com",gamma:"gamma-a.locuslabs.com",prod:"a.locuslabs.com"},{assetStage:o,venueId:c,accountId:n,formatVersion:u}=t,l=`https://${s[o]||s.prod}/accounts/${n}`,i=u||"v5",h=t.dataFetch&&e[t.dataFetch]&&e[t.dataFetch].getFiles?await e[t.dataFetch].getFiles(t):await a(`${l}/${i}.json`);if(!h[c])throw Error(`Attempt to access venue ${c} which is not within venue list: ${Object.keys(h)}`);const d=h[c].files,m=(t.dataFetch&&e[t.dataFetch]&&e[t.dataFetch].getVenueData?await e[t.dataFetch].getVenueData(t):await a(d.venueData))[c];m.venueList=h;const p=(t=>{const a=t.deepLinkProps?t.deepLinkProps.contentStage:null;return"alpha"===a||"beta"===a||"prod"===a?a:null})(t);return m.files=p?r(m.category,d,p,n,c):d,m},l=t=>{const{structureOrder:e,structures:s}=t;return e.map((t=>{const e=s[t],o=a(e.boundsPolygon);return{...e,bounds:o}}))};export{l as buildStructures,o as createFetchJson,c as createFetchText,u as getVenueDataFromUrls};