atriusmaps-node-sdk 3.3.892 → 3.3.894

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.
@@ -3,10 +3,10 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var name = "web-engine";
6
- var version = "3.3.892";
6
+ var version = "3.3.894";
7
7
  var license = "UNLICENSED";
8
8
  var type = "module";
9
- var main = "src/main.js";
9
+ var main = "src/main.ts";
10
10
  var workspaces = [
11
11
  "demo",
12
12
  "deploy",
@@ -17,7 +17,7 @@ var workspaces = [
17
17
  ];
18
18
  var scripts = {
19
19
  "build-storybook": "storybook build",
20
- colors: "cat utils/colors1.txt && node utils/processColors.js | pbcopy && cat utils/colors2.txt",
20
+ colors: "cat utils/colors1.txt && node --experimental-strip-types utils/processColors.ts | pbcopy && cat utils/colors2.txt",
21
21
  demo: "cd demo/ && yarn start",
22
22
  dev: "yarn mol e2e",
23
23
  "format:check": "yarn prettier . --check",
@@ -128,25 +128,18 @@ var devDependencies = {
128
128
  "@vitest/browser": "4.1.6",
129
129
  "@vitest/browser-playwright": "4.1.6",
130
130
  "@vitest/ui": "4.1.6",
131
- "chai-colors": "^1.0.1",
132
131
  "css-loader": "^7.1.2",
133
132
  eslint: "^8.57.1",
134
133
  "eslint-config-prettier": "^10.1.8",
135
- "eslint-config-standard": "^17.1.0",
136
134
  "eslint-import-resolver-alias": "^1.1.2",
137
- "eslint-plugin-n": "^17.16.2",
138
- "eslint-plugin-node": "^11.1.0",
139
135
  "eslint-plugin-playwright": "^2.2.2",
140
- "eslint-plugin-promise": "^5.2.0",
141
136
  "eslint-plugin-react": "^7.37.4",
142
- "eslint-plugin-standard": "^5.0.0",
143
137
  "eslint-plugin-vitest": "^0.5.4",
144
138
  "fetch-mock": "^12.6.0",
145
139
  glob: "^11.0.1",
146
140
  husky: "^9.1.7",
147
141
  "lint-staged": "^16.4.0",
148
142
  "node-fetch": "^2.7.0",
149
- "null-loader": "^4.0.1",
150
143
  nx: "19.8.14",
151
144
  "nx-remotecache-azure": "^19.0.0",
152
145
  "os-browserify": "^0.3.0",
@@ -174,7 +167,7 @@ var pkg = {
174
167
  workspaces: workspaces,
175
168
  scripts: scripts,
176
169
  "lint-staged": {
177
- "*.js": [
170
+ "*.{js,ts,tsx}": [
178
171
  "eslint --fix",
179
172
  "prettier --check"
180
173
  ],
@@ -182,7 +175,7 @@ var pkg = {
182
175
  "prettier --check"
183
176
  ],
184
177
  "src/i18n/**/*.json": [
185
- "node utils/sort-json.js",
178
+ "node --experimental-strip-types utils/sort-json.ts",
186
179
  "prettier --write"
187
180
  ]
188
181
  },
@@ -98,11 +98,15 @@ function mapFlightDetails(nowDate, flight, T, tz, locale) {
98
98
  // used to sort flights in ASCENDING order of flight arrival/departure time
99
99
  const flightComparator = (flight1, flight2) => flight1.dateStamp - flight2.dateStamp;
100
100
 
101
+ // Matches gate identifiers: optional letter prefix + digits + optional letter suffix (e.g. "B54", "23", "B32a")
102
+ const gateNameRegex = /[A-Z]?\d+[a-zA-Z]?/;
103
+
101
104
  const formatGate = gate => {
102
105
  if (!gate) {
103
106
  return { name: '-' };
104
107
  }
105
- const name = R.last(gate.name.split(' '));
108
+ const match = gate.name.match(gateNameRegex);
109
+ const name = match ? match[0] : gate.name;
106
110
  return { ...gate, name };
107
111
  };
108
112
 
@@ -246,5 +250,7 @@ const getLocalFormattedTime = (dateStr, tz, locale = 'en-US') =>
246
250
 
247
251
  exports.FlightType = FlightType;
248
252
  exports.flightComparator = flightComparator;
253
+ exports.formatGate = formatGate;
254
+ exports.gateNameRegex = gateNameRegex;
249
255
  exports.mapFlightDetails = mapFlightDetails;
250
256
  exports.mapFlightListItem = mapFlightListItem;
@@ -219,10 +219,11 @@ function create(app, config) {
219
219
 
220
220
  if (p.indexOf(',') > 0) {
221
221
  // lat,lng,floorId,desc format
222
- let [lat, lng, floorId, title] = p.split(',');
222
+ const [lat, lng, floorId, initialTitle] = p.split(',');
223
223
  if (!graph.floorIdToStructureId(floorId)) {
224
224
  throw Error('Unknown floorId in endpoint: ' + floorId);
225
225
  }
226
+ let title = initialTitle;
226
227
  if (!title) {
227
228
  title = 'Starting Point';
228
229
  }
@@ -9,7 +9,6 @@ function userInteractionHandler() {
9
9
  if (!userInteracted) {
10
10
  userInteracted = true;
11
11
  for (const cb of callbacks) {
12
- // eslint-disable-next-line n/no-callback-literal
13
12
  cb(true);
14
13
  }
15
14
  callbacks.clear();
@@ -18,7 +18,8 @@ async function locationToEndpoint(app, location) {
18
18
  });
19
19
  }
20
20
 
21
- let { lat, lng, ord, ordinal, floorId, title = '', structureId } = location;
21
+ const { lat, lng, ord, title = '' } = location;
22
+ let { ordinal, floorId, structureId } = location;
22
23
 
23
24
  if (lat == null || lng == null) {
24
25
  throw Error('To obtain a location, you must provide a lat,lng or a poiId');
@@ -1 +1 @@
1
- var t="web-engine",e="3.3.892",s="UNLICENSED",r="module",o="src/main.js",i=["demo","deploy","nodesdk","src/extModules/flexapi","services/*","libraries/*"],a={"build-storybook":"storybook build",colors:"cat utils/colors1.txt && node utils/processColors.js | pbcopy && cat utils/colors2.txt",demo:"cd demo/ && yarn start",dev:"yarn mol e2e","format:check":"yarn prettier . --check","format:fix":"yarn prettier . --write",goProd:"cd deploy && scripts/goProd.sh",goStaging:"deploy/scripts/goStaging.sh","icons:convert":"node scripts/convertSvgToJsx.mjs",lint:"eslint . --ext .js,.jsx,.ts,.tsx",mod:"demo/startMod.sh",mol:"demo/startMol.sh","mol:build":"demo/startMolBuild.sh",molProd:"cd deploy && yarn buildAndRunMol","playwright:ci":"yarn playwright test --grep-invert sdk","playwright:ci:failed":"yarn playwright test --last-failed --grep-invert sdk","playwright:sdk":"yarn start-server-and-test 'cd ./deploy && yarn buildDev && yarn serveLocal' 8085 'cd ./test/sdk && npx http-server' 8080 'yarn playwright test sdk --ui'","playwright:ui":"yarn playwright test --ui --grep-invert sdk",prepare:"husky",storybook:"storybook dev -p 6006",test:"vitest run --project unit","test-watch":"vitest --watch","test:comp":"vitest run --project browser","test:comp:ci":"vitest run --project browser --reporter=dot","test:comp:ui":"VITE_COMP_UI=1 vitest --project browser --ui --browser.headless=false","test:all":"yarn lint && yarn format:check && yarn test && yarn playwright:ci","test:mod":"playwright test --config=playwright.mod.config.ts",typecheck:"tsc -p tsconfig.checkjs.json"},l=["defaults"],n={"@azure/event-hubs":"^5.12.2","@csstools/normalize.css":"^11.0.1","@dnd-kit/core":"^6.3.1","@dnd-kit/modifiers":"^9.0.0","@dnd-kit/sortable":"^10.0.0","@dnd-kit/utilities":"^3.2.2","@mapbox/mapbox-gl-draw":"^1.5.0","@mapbox/mapbox-gl-draw-static-mode":"^1.0.1","@microsoft/applicationinsights-web":"^3.3.6","@styled-system/prop-types":"^5.1.5","@turf/area":"^7.2.0","@turf/bbox-clip":"^7.2.0","@turf/bbox-polygon":"^7.2.0","@turf/bearing":"^7.2.0","@turf/circle":"^7.2.0","@turf/helpers":"^7.2.0","@turf/point-to-line-distance":"^7.2.0","@vitejs/plugin-react":"^5.2.0","@zumer/snapdom":"^2.9.0","axe-core":"^4.10.3",browserslist:"^4.27.0","crypto-browserify":"^3.12.1",dompurify:"^3.3.3","file-loader":"^6.2.0",flexsearch:"^0.7.43","h3-js":"^4.1.0",i18next:"^26.0.0","i18next-browser-languagedetector":"^6.1.1",jsdom:"^25.0.1",jsonschema:"^1.5.0",luxon:"^3.5.0","maplibre-gl":"^4.7.1","mini-css-extract-plugin":"^2.9.2","node-polyfill-webpack-plugin":"^4.1.0","path-browserify":"^1.0.1",pmtiles:"^4.4.0","prop-types":"^15.8.1","qrcode.react":"^4.2.0",ramda:"^0.30.1",react:"^19.2.4","react-compound-slider":"^3.4.0","react-dom":"^19.2.4","react-json-editor-ajrm":"^2.5.14","react-svg":"^16.3.0","react-virtualized-auto-sizer":"^1.0.25","react-window":"^1.8.11","smoothscroll-polyfill":"^0.4.4","styled-components":"^6.1.15","styled-normalize":"^8.1.1","styled-system":"^5.1.5","styled-tools":"^1.7.2","throttle-debounce":"^5.0.2",trackjs:"^3.10.4","ua-parser-js":"^0.7.40",uuid:"^11.1.0",zousan:"^3.0.1","zousan-plus":"^4.0.1"},c={"@applitools/eyes-playwright":"^1.46.8","@axe-core/playwright":"^4.10.2","@azure/identity":"^4.13.0","@azure/playwright":"^1.0.0","@playwright/test":"~1.59.1","@storybook/addon-essentials":"^8.6.15","@storybook/blocks":"^8.6.15","@storybook/react":"^8.6.15","@storybook/react-vite":"^8.6.15","@testing-library/dom":"^10.4.1","@testing-library/jest-dom":"^6.6.3","@testing-library/react":"^16.3.0","@testing-library/user-event":"^14.5.2","@types/react":"^19.0.10","@types/react-dom":"^19.0.4","@typescript-eslint/eslint-plugin":"^8.26.1","@typescript-eslint/parser":"^8.26.1","@vitest/browser":"4.1.6","@vitest/browser-playwright":"4.1.6","@vitest/ui":"4.1.6","chai-colors":"^1.0.1","css-loader":"^7.1.2",eslint:"^8.57.1","eslint-config-prettier":"^10.1.8","eslint-config-standard":"^17.1.0","eslint-import-resolver-alias":"^1.1.2","eslint-plugin-n":"^17.16.2","eslint-plugin-node":"^11.1.0","eslint-plugin-playwright":"^2.2.2","eslint-plugin-promise":"^5.2.0","eslint-plugin-react":"^7.37.4","eslint-plugin-standard":"^5.0.0","eslint-plugin-vitest":"^0.5.4","fetch-mock":"^12.6.0",glob:"^11.0.1",husky:"^9.1.7","lint-staged":"^16.4.0","node-fetch":"^2.7.0","null-loader":"^4.0.1",nx:"19.8.14","nx-remotecache-azure":"^19.0.0","os-browserify":"^0.3.0",prettier:"^3.8.3","start-server-and-test":"^2.0.11",storybook:"^8.6.15",typescript:"^5.8.2",vite:"^7.3.2",vitest:"^4.1.8","webpack-merge":"^6.0.1"},p="yarn@4.13.0",d={node:"24.x"},y={},u={name:t,version:e,private:!0,license:s,type:r,main:o,workspaces:i,scripts:a,"lint-staged":{"*.js":["eslint --fix","prettier --check"],"*.{json,md,css,ts,tsx,jsx}":["prettier --check"],"src/i18n/**/*.json":["node utils/sort-json.js","prettier --write"]},browserslist:l,dependencies:n,devDependencies:c,packageManager:p,engines:d,nx:y};export{l as browserslist,u as default,n as dependencies,c as devDependencies,d as engines,s as license,o as main,t as name,y as nx,p as packageManager,a as scripts,r as type,e as version,i as workspaces};
1
+ var t="web-engine",e="3.3.894",s="UNLICENSED",r="module",o="src/main.ts",i=["demo","deploy","nodesdk","src/extModules/flexapi","services/*","libraries/*"],a={"build-storybook":"storybook build",colors:"cat utils/colors1.txt && node --experimental-strip-types utils/processColors.ts | pbcopy && cat utils/colors2.txt",demo:"cd demo/ && yarn start",dev:"yarn mol e2e","format:check":"yarn prettier . --check","format:fix":"yarn prettier . --write",goProd:"cd deploy && scripts/goProd.sh",goStaging:"deploy/scripts/goStaging.sh","icons:convert":"node scripts/convertSvgToJsx.mjs",lint:"eslint . --ext .js,.jsx,.ts,.tsx",mod:"demo/startMod.sh",mol:"demo/startMol.sh","mol:build":"demo/startMolBuild.sh",molProd:"cd deploy && yarn buildAndRunMol","playwright:ci":"yarn playwright test --grep-invert sdk","playwright:ci:failed":"yarn playwright test --last-failed --grep-invert sdk","playwright:sdk":"yarn start-server-and-test 'cd ./deploy && yarn buildDev && yarn serveLocal' 8085 'cd ./test/sdk && npx http-server' 8080 'yarn playwright test sdk --ui'","playwright:ui":"yarn playwright test --ui --grep-invert sdk",prepare:"husky",storybook:"storybook dev -p 6006",test:"vitest run --project unit","test-watch":"vitest --watch","test:comp":"vitest run --project browser","test:comp:ci":"vitest run --project browser --reporter=dot","test:comp:ui":"VITE_COMP_UI=1 vitest --project browser --ui --browser.headless=false","test:all":"yarn lint && yarn format:check && yarn test && yarn playwright:ci","test:mod":"playwright test --config=playwright.mod.config.ts",typecheck:"tsc -p tsconfig.checkjs.json"},l=["defaults"],n={"@azure/event-hubs":"^5.12.2","@csstools/normalize.css":"^11.0.1","@dnd-kit/core":"^6.3.1","@dnd-kit/modifiers":"^9.0.0","@dnd-kit/sortable":"^10.0.0","@dnd-kit/utilities":"^3.2.2","@mapbox/mapbox-gl-draw":"^1.5.0","@mapbox/mapbox-gl-draw-static-mode":"^1.0.1","@microsoft/applicationinsights-web":"^3.3.6","@styled-system/prop-types":"^5.1.5","@turf/area":"^7.2.0","@turf/bbox-clip":"^7.2.0","@turf/bbox-polygon":"^7.2.0","@turf/bearing":"^7.2.0","@turf/circle":"^7.2.0","@turf/helpers":"^7.2.0","@turf/point-to-line-distance":"^7.2.0","@vitejs/plugin-react":"^5.2.0","@zumer/snapdom":"^2.9.0","axe-core":"^4.10.3",browserslist:"^4.27.0","crypto-browserify":"^3.12.1",dompurify:"^3.3.3","file-loader":"^6.2.0",flexsearch:"^0.7.43","h3-js":"^4.1.0",i18next:"^26.0.0","i18next-browser-languagedetector":"^6.1.1",jsdom:"^25.0.1",jsonschema:"^1.5.0",luxon:"^3.5.0","maplibre-gl":"^4.7.1","mini-css-extract-plugin":"^2.9.2","node-polyfill-webpack-plugin":"^4.1.0","path-browserify":"^1.0.1",pmtiles:"^4.4.0","prop-types":"^15.8.1","qrcode.react":"^4.2.0",ramda:"^0.30.1",react:"^19.2.4","react-compound-slider":"^3.4.0","react-dom":"^19.2.4","react-json-editor-ajrm":"^2.5.14","react-svg":"^16.3.0","react-virtualized-auto-sizer":"^1.0.25","react-window":"^1.8.11","smoothscroll-polyfill":"^0.4.4","styled-components":"^6.1.15","styled-normalize":"^8.1.1","styled-system":"^5.1.5","styled-tools":"^1.7.2","throttle-debounce":"^5.0.2",trackjs:"^3.10.4","ua-parser-js":"^0.7.40",uuid:"^11.1.0",zousan:"^3.0.1","zousan-plus":"^4.0.1"},p={"@applitools/eyes-playwright":"^1.46.8","@axe-core/playwright":"^4.10.2","@azure/identity":"^4.13.0","@azure/playwright":"^1.0.0","@playwright/test":"~1.59.1","@storybook/addon-essentials":"^8.6.15","@storybook/blocks":"^8.6.15","@storybook/react":"^8.6.15","@storybook/react-vite":"^8.6.15","@testing-library/dom":"^10.4.1","@testing-library/jest-dom":"^6.6.3","@testing-library/react":"^16.3.0","@testing-library/user-event":"^14.5.2","@types/react":"^19.0.10","@types/react-dom":"^19.0.4","@typescript-eslint/eslint-plugin":"^8.26.1","@typescript-eslint/parser":"^8.26.1","@vitest/browser":"4.1.6","@vitest/browser-playwright":"4.1.6","@vitest/ui":"4.1.6","css-loader":"^7.1.2",eslint:"^8.57.1","eslint-config-prettier":"^10.1.8","eslint-import-resolver-alias":"^1.1.2","eslint-plugin-playwright":"^2.2.2","eslint-plugin-react":"^7.37.4","eslint-plugin-vitest":"^0.5.4","fetch-mock":"^12.6.0",glob:"^11.0.1",husky:"^9.1.7","lint-staged":"^16.4.0","node-fetch":"^2.7.0",nx:"19.8.14","nx-remotecache-azure":"^19.0.0","os-browserify":"^0.3.0",prettier:"^3.8.3","start-server-and-test":"^2.0.11",storybook:"^8.6.15",typescript:"^5.8.2",vite:"^7.3.2",vitest:"^4.1.8","webpack-merge":"^6.0.1"},c="yarn@4.13.0",d={node:"24.x"},y={},u={name:t,version:e,private:!0,license:s,type:r,main:o,workspaces:i,scripts:a,"lint-staged":{"*.{js,ts,tsx}":["eslint --fix","prettier --check"],"*.{json,md,css,ts,tsx,jsx}":["prettier --check"],"src/i18n/**/*.json":["node --experimental-strip-types utils/sort-json.ts","prettier --write"]},browserslist:l,dependencies:n,devDependencies:p,packageManager:c,engines:d,nx:y};export{l as browserslist,u as default,n as dependencies,p as devDependencies,d as engines,s as license,o as main,t as name,y as nx,c as packageManager,a as scripts,r as type,e as version,i as workspaces};
@@ -1 +1 @@
1
- import{DateTime as t}from"luxon";import{pick as e,propOr as a,last as r,compose as i,path as l}from"ramda";import{formatTime as s,msToMin as o}from"../../../src/utils/date.js";import{FlightLabelStatus as n}from"../../../utils/constants.js";const m={ARRIVAL:"arr",DEPARTURE:"dep",ALL:"all"};function u(t,e,r,i,l){const{flightId:s,carrierFsCode:o,flightNumber:n,airline:u,flightType:d,departureAirport:g,arrivalAirport:D,airportResources:f,gatePoi:p,status:E}=e,L=A(e),{localTime:C,localOldTime:U}=R(L,i),P=h(d,E,t,C,U),$=d===m.DEPARTURE?"flightDetails:Departs _date_":"flightDetails:Arrives _date_";return{flightId:s,name:`${a("","name",u)} - ${o} ${n}`,status:P,statusText:r(`flightDetails:${T(P)}`),baggageClaim:d===m.ARRIVAL?I(f.arrivalBagClaim,r):void 0,connectionAirport:v(d,g,D,r),time:N(C,i,l),oldTime:N(U,i,l),date:r($,{date:_(C,i,l)}),dateStamp:C.toMillis(),gate:c(p),gateLabel:r("flightDetails:Gate")}}function d(t,r,i,l,s){const{flightNumber:o,flightType:n,departureAirport:u,arrivalAirport:d,airportResources:g,flightStatusUpdates:p,carrierFsCode:E,gatePoi:L,airline:C,status:U}=r,P=e(["city","iata"]),$=A(r),{localTime:y,localOldTime:O}=R($,l),S=h(n,U,t,y,O);return{flightType:n,flightTypeLabel:i(`flightDetails:${n===m.DEPARTURE?"Departure":"Arrival"}`),name:`${a("","name",C)} - ${E} ${o}`,status:S,statusText:i(`flightDetails:${T(S)}`),baggageClaim:n===m.ARRIVAL?I(g.arrivalBagClaim,i):void 0,departure:P(u),arrival:P(d),connectionAirport:v(n,u,d,i),flightIn:D(S,n,t,y,i),time:N(y,l,s),oldTime:N(O,l,s),date:_(y,l,s),lastUpdated:f(t,p,i),flightDuration:"",gateLabel:i("flightDetails:Gate"),gate:c(L),tags:[],flightIconBaseName:n===m.ARRIVAL?"arrivals":"departures"}}const g=(t,e)=>t.dateStamp-e.dateStamp,c=t=>{if(!t)return{name:"-"};const e=r(t.name.split(" "));return{...t,name:e}},D=(t,e,a,r,i)=>{if(t===n.DEPARTED)return i("flightDetails:Departed");if(t===n.ARRIVED)return i("flightDetails:Arrived");if(t===n.CANCELLED)return null;return i(`flightDetails:${e===m.DEPARTURE?"Departs":"Arrives"} in _minutes_ minute`,{count:p(a,r)})},f=(t,e,a)=>{const s=i(l(["updatedAt","dateUtc"]),r)(e),o=p(t,U(s));return o<10?a("flightDetails:Last updated a few minutes ago"):o<60?a("flightDetails:Last updated _minutes_ minutes ago",{minutes:o}):a("flightDetails:Last updated over an hour ago")},p=(t,e)=>{const a=Math.abs(t-e);return o(a)},A=({flightType:t,operationalTimes:e,departureDate:a,arrivalDate:r})=>t===m.DEPARTURE?E(a,e.estimatedGateDeparture):E(r,e.estimatedGateArrival),E=(t,e)=>{const a=t.dateLocal||t.dateUtc,r=e.dateLocal||e.dateUtc;return r&&a!==r?{time:r,oldTime:a}:{time:a}},R=({time:t,oldTime:e},a)=>({localTime:U(t,a),localOldTime:U(e,a)});function h(t,e,a,r,i){return r?a>r?L(t):"C"===(e=e.toUpperCase())?n.CANCELLED:i?r>i?n.DELAYED:n.EARLY:n.ON_TIME:n.UNKNOWN}const T=t=>{switch(t){case n.ON_TIME:return"on-time";case n.EARLY:return"early";case n.DELAYED:return"delayed";case n.CANCELLED:return"cancelled";case n.DEPARTED:return"departed";case n.ARRIVED:return"arrived";default:return"unknown"}},L=t=>t===m.DEPARTURE?n.DEPARTED:n.ARRIVED,v=(t,e,a,r)=>t===m.DEPARTURE?r(C("To"),a):r(C("From"),e),C=t=>`flightDetails:${t} _city_ (_iata_)`,I=(t,e)=>t&&e("flightDetails:Collect luggage from Baggage Claim _claimNum_",{claimNum:t}),U=(e,a)=>e&&t.fromISO(e,{zone:a}),_=(e,a,r="en-US")=>e&&t.fromISO(e,{zone:a}).setLocale(r).toFormat("EEE, d MMMM"),N=(e,a,r="en-US")=>e&&s(t.fromISO(e,{zone:a}),r);export{m as FlightType,g as flightComparator,d as mapFlightDetails,u as mapFlightListItem};
1
+ import{DateTime as t}from"luxon";import{pick as e,propOr as a,compose as r,path as i,last as l}from"ramda";import{formatTime as o,msToMin as s}from"../../../src/utils/date.js";import{FlightLabelStatus as n}from"../../../utils/constants.js";const m={ARRIVAL:"arr",DEPARTURE:"dep",ALL:"all"};function u(t,e,r,i,l){const{flightId:o,carrierFsCode:s,flightNumber:n,airline:u,flightType:d,departureAirport:g,arrivalAirport:c,airportResources:f,gatePoi:A,status:p}=e,R=E(e),{localTime:v,localOldTime:I}=h(R,i),_=T(d,p,t,v,I),$=d===m.DEPARTURE?"flightDetails:Departs _date_":"flightDetails:Arrives _date_";return{flightId:o,name:`${a("","name",u)} - ${s} ${n}`,status:_,statusText:r(`flightDetails:${L(_)}`),baggageClaim:d===m.ARRIVAL?U(f.arrivalBagClaim,r):void 0,connectionAirport:C(d,g,c,r),time:P(v,i,l),oldTime:P(I,i,l),date:r($,{date:N(v,i,l)}),dateStamp:v.toMillis(),gate:D(A),gateLabel:r("flightDetails:Gate")}}function d(t,r,i,l,o){const{flightNumber:s,flightType:n,departureAirport:u,arrivalAirport:d,airportResources:g,flightStatusUpdates:c,carrierFsCode:p,gatePoi:R,airline:v,status:I}=r,_=e(["city","iata"]),$=E(r),{localTime:y,localOldTime:O}=h($,l),S=T(n,I,t,y,O);return{flightType:n,flightTypeLabel:i(`flightDetails:${n===m.DEPARTURE?"Departure":"Arrival"}`),name:`${a("","name",v)} - ${p} ${s}`,status:S,statusText:i(`flightDetails:${L(S)}`),baggageClaim:n===m.ARRIVAL?U(g.arrivalBagClaim,i):void 0,departure:_(u),arrival:_(d),connectionAirport:C(n,u,d,i),flightIn:f(S,n,t,y,i),time:P(y,l,o),oldTime:P(O,l,o),date:N(y,l,o),lastUpdated:A(t,c,i),flightDuration:"",gateLabel:i("flightDetails:Gate"),gate:D(R),tags:[],flightIconBaseName:n===m.ARRIVAL?"arrivals":"departures"}}const g=(t,e)=>t.dateStamp-e.dateStamp,c=/[A-Z]?\d+[a-zA-Z]?/,D=t=>{if(!t)return{name:"-"};const e=t.name.match(c),a=e?e[0]:t.name;return{...t,name:a}},f=(t,e,a,r,i)=>{if(t===n.DEPARTED)return i("flightDetails:Departed");if(t===n.ARRIVED)return i("flightDetails:Arrived");if(t===n.CANCELLED)return null;return i(`flightDetails:${e===m.DEPARTURE?"Departs":"Arrives"} in _minutes_ minute`,{count:p(a,r)})},A=(t,e,a)=>{const o=r(i(["updatedAt","dateUtc"]),l)(e),s=p(t,_(o));return s<10?a("flightDetails:Last updated a few minutes ago"):s<60?a("flightDetails:Last updated _minutes_ minutes ago",{minutes:s}):a("flightDetails:Last updated over an hour ago")},p=(t,e)=>{const a=Math.abs(t-e);return s(a)},E=({flightType:t,operationalTimes:e,departureDate:a,arrivalDate:r})=>t===m.DEPARTURE?R(a,e.estimatedGateDeparture):R(r,e.estimatedGateArrival),R=(t,e)=>{const a=t.dateLocal||t.dateUtc,r=e.dateLocal||e.dateUtc;return r&&a!==r?{time:r,oldTime:a}:{time:a}},h=({time:t,oldTime:e},a)=>({localTime:_(t,a),localOldTime:_(e,a)});function T(t,e,a,r,i){return r?a>r?v(t):"C"===(e=e.toUpperCase())?n.CANCELLED:i?r>i?n.DELAYED:n.EARLY:n.ON_TIME:n.UNKNOWN}const L=t=>{switch(t){case n.ON_TIME:return"on-time";case n.EARLY:return"early";case n.DELAYED:return"delayed";case n.CANCELLED:return"cancelled";case n.DEPARTED:return"departed";case n.ARRIVED:return"arrived";default:return"unknown"}},v=t=>t===m.DEPARTURE?n.DEPARTED:n.ARRIVED,C=(t,e,a,r)=>t===m.DEPARTURE?r(I("To"),a):r(I("From"),e),I=t=>`flightDetails:${t} _city_ (_iata_)`,U=(t,e)=>t&&e("flightDetails:Collect luggage from Baggage Claim _claimNum_",{claimNum:t}),_=(e,a)=>e&&t.fromISO(e,{zone:a}),N=(e,a,r="en-US")=>e&&t.fromISO(e,{zone:a}).setLocale(r).toFormat("EEE, d MMMM"),P=(e,a,r="en-US")=>e&&o(t.fromISO(e,{zone:a}),r);export{m as FlightType,g as flightComparator,D as formatGate,c as gateNameRegex,d as mapFlightDetails,u as mapFlightListItem};
@@ -1 +1 @@
1
- import*as t from"ramda";import n from"zousan";import{buildStructuresLookup as o}from"../../../src/utils/buildStructureLookup.js";import{distance as e}from"../../../src/utils/geodesy.js";import{findRoute as i}from"./findRoute.js";import{createNavGraph as r}from"./navGraph.js";import{enrichDebugNavGraph as a}from"./navGraphDebug.js";import{buildSegments as s}from"./segmentBuilder.js";const u={SECURITY:"SecurityLane",IMMIGRATION:"ImmigrationLane"};function d(d,l){const p=d.log.sublog("wayfinder"),c=async()=>{d.bus.send("venueData/loadNavGraph")};let f=new n;d.bus.on("wayfinder/_getNavGraph",()=>f),d.bus.on("venueData/navGraphLoaded",async({navGraphData:t,structures:n})=>{const e=o(n),i=await m(),a=r(t,e.floorIdToOrdinal,e.floorIdToStructureId,i);f.resolve(a)}),d.bus.on("poi/setDynamicRouting",async({idValuesMap:t})=>{const n=await f,o=Object.values(t).filter(t=>t.position&&void 0!==t.position.floorId&&t.position.latitude&&t.position.longitude).map(t=>n.findClosestNode(t.position.floorId,t.position.latitude,t.position.longitude).id);n.addNodesToAvoid(o)});const m=async()=>{const n=await d.bus.get("poi/getByCategoryId",{categoryId:"security"});return t.pipe(t.map(y),t.filter(t.identity))(n)},y=n=>n.queue&&{type:t.path(["queue","queueType"],n),id:t.path(["queue","queueSubtype"],n)};d.bus.on("wayfinder/showNavLineFromPhysicalLocation",async({toEndpoint:t,selectedSecurityLanes:n=null,requiresAccessibility:o})=>async function(t,n,o){const e=await T({fromEndpoint:t,toEndpoint:n,options:o});if(e){const{segments:t}=e;o.primary&&d.bus.send("map/resetNavlineFeatures"),d.bus.send("map/showNavlineFeatures",{segments:t,category:o.primary?"primary":"alternative"})}return e}(await d.bus.getFirst("user/getPhysicalLocation"),t,{selectedSecurityLanes:n,requiresAccessibility:o,primary:!0}));const g=(t,n)=>d.bus.get("poi/getById",{id:t}).then(o=>{if(o&&o.position)return w(o,n);throw Error("Unknown POI ID "+t)});const h=["lat","lng","floorId","ordinal"],I=t.pipe(t.pick(h),t.keys,t.propEq(h.length,"length"),Boolean),w=(t,n)=>({lat:t.position.latitude,lng:t.position.longitude,floorId:t.position.floorId,ordinal:n(t.position.floorId),title:t.name});async function T({fromEndpoint:t,toEndpoint:n,options:o={}}){const e=await d.bus.get("poi/getAll")||{},r=Array.isArray(e)?e[0]:e,a=Object.values(r).filter(t=>t.category&&t.category.startsWith("security")),u=await d.bus.getFirst("directions/getPreferredUnits")||"meters";return f.then(async e=>{o.compareFindPaths=l.compareFindPaths;const r=i(e,t,n,o);if(!r)return null;const c=await d.bus.get("venueData/getFloorIdToNameMap"),f=await d.bus.get("venueData/getQueueTypes"),m=d.gt(),y=o.requiresAccessibility,{steps:g,segments:h}=s(r.waypoints,t,n,c,m,f,y,a,u);p.info("route",r);const I=Math.round(r.waypoints.reduce((t,{eta:n})=>t+n,0)),w=Math.round(r.waypoints.reduce((t,{distance:n})=>t+n,0));return{...r,segments:h,steps:g,time:I,distance:w}})}function b(n,o,e,i){let r=t.clone(n);return r=E(r,e,i),o&&o.length?{...r,transitTime:v(o,"transitTime"),distance:v(o,"distance")}:(r.distance="start"===i?O(r,e):O(e,r),r.transitTime=S(r.distance),r)}function v(n,o){return t.aperture(2,n).map(([n,o])=>{return(e=o.id,n=>t.find(t=>t.dst===e,n.edges))(n);var e}).map(t.prop(o)).reduce((t,n)=>t+n,0)}function E(t,n,o){return{...t,[o+"Information"]:{lat:n?.lat||n?.position?.latitude,lng:n?.lng||n?.position?.longitude,floorId:n?.floorId||n?.position?.floorId}}}function O(t,n){return e(n?.lat||n?.position?.latitude,n?.lng||n?.position?.longitude,t?.lat||t?.position?.latitude,t?.lng||t?.position?.longitude)}function S(t){return t/60}function L(n){const o=n.filter(t=>null!==t);return t.sortBy(t.propOr(1/0,"transitTime"),o)}function N(t,n){return t&&t.length?v(t,"transitTime"):S(n)}function P(t,n,o){return t&&t.length?v(t,"distance"):O(o,n)}return d.bus.on("wayfinder/getNavigationEndpoint",({ep:t})=>async function(t){return f.then(n=>{if(!t)throw Error("wayfinder: Invalid endpoint definition",t);if("number"==typeof t)return g(t,n.floorIdToOrdinal);if("string"==typeof t){if(t.match(/^\d+$/))return g(parseInt(t),n.floorIdToOrdinal);if(t.indexOf(",")>0){let[o,e,i,r]=t.split(",");if(!n.floorIdToStructureId(i))throw Error("Unknown floorId in endpoint: "+i);return r||(r="Starting Point"),{lat:parseFloat(o),lng:parseFloat(e),ordinal:n.floorIdToOrdinal(i),floorId:i,title:r}}}if(I(t))return t;if(t.latitude)return{lat:t.latitude,lng:t.longitude,floorId:t.floorId,ordinal:n.floorIdToOrdinal(t.floorId),title:t.title};if(t.position&&t.name)return w(t,n.floorIdToOrdinal);throw Error("Invalid start or end point: "+t)})}(t)),d.bus.on("wayfinder/checkIfPathHasSecurity",({fromEndpoint:n,toEndpoint:o,options:e={}})=>f.then(r=>{e.compareFindPaths=l.compareFindPaths;const a=i(r,n,o,e);if(!a)return{routeExists:!1};const s=n=>Boolean(a.waypoints.find(t.pathEq(n,["securityLane","type"])));return{routeExists:!0,queues:a.waypoints.filter(n=>t.pathEq(u.SECURITY,["securityLane","type"],n)||t.pathEq(u.IMMIGRATION,["securityLane","type"],n)),hasSecurity:s(u.SECURITY),hasImmigration:s(u.IMMIGRATION)}})),d.bus.on("wayfinder/getRoute",T),d.bus.on("wayfinder/addPathTimeMultiple",async({pois:n,startLocation:o,options:e={}})=>o?f.then(i=>function(n,o,e,i){try{const r=t.clone(e),a=r.map(t=>w(t,n.floorIdToOrdinal)),s=n.findAllShortestPaths(i,a,o);return L(r.map((t,n)=>b(t,s[n],i,"start")))}catch(t){return p.error(t),e}}(i,e,n,o)):n),d.bus.on("wayfinder/multipointAddPathTimeMultiple",async({pois:n,startLocation:o,endLocation:e,currentLocation:i,options:r={}})=>o||e||i?f.then(a=>function(n,o,e,i,r,a){try{const s=i?w(i,n.floorIdToOrdinal):a,u=r?w(r,n.floorIdToOrdinal):null,d=t.clone(e),l=d.map(t=>w(t,n.floorIdToOrdinal));let p,c,f;return s&&(p=n.findAllShortestPaths(s,l,o)),u&&(c=function(t,n,o,e){const i=[];for(const r of n)i.push(t.findShortestPath(r,o,e));return i}(n,l,u,o)),f=s&&u?d.map((n,o)=>function(n,o,e,i,r){const a=P(o,i,n),s=P(e,n,r);if(!a||!s)return null;const u=N(o,a),d=N(e,s);let l=t.clone(n);return l=E(l,i,"start"),l=E(l,r,"end"),{...l,transitTime:u+d,distance:a+s,startInformation:{...l.startInformation,transitTime:u,distance:a},endInformation:{...l.endInformation,transitTime:d,distance:s}}}(n,p[o],c[o],s,u)):s?d.map((t,n)=>b(t,p[n],s,"start")):d.map((t,n)=>b(t,c[n],u,"end")),L(f)}catch(t){return p.error(t),e}}(a,r,n,o,e,i)):n),d.bus.on("venueData/loadNewVenue",()=>{f=new n,c()}),d.bus.on("poi/setDynamicData",({plugin:t,idValuesMap:n})=>{"security"===t&&f.then(t=>t.updateWithSecurityWaitTime(n))}),d.bus.on("wayfinder/getNavGraphFeatures",()=>f.then(({_nodes:t})=>a(t))),{init:c,internal:{resolveNavGraph:t=>f.resolve(t),prepareSecurityLanes:m}}}export{u as SecurityLaneType,d as create};
1
+ import*as t from"ramda";import n from"zousan";import{buildStructuresLookup as o}from"../../../src/utils/buildStructureLookup.js";import{distance as e}from"../../../src/utils/geodesy.js";import{findRoute as i}from"./findRoute.js";import{createNavGraph as r}from"./navGraph.js";import{enrichDebugNavGraph as a}from"./navGraphDebug.js";import{buildSegments as s}from"./segmentBuilder.js";const u={SECURITY:"SecurityLane",IMMIGRATION:"ImmigrationLane"};function d(d,l){const p=d.log.sublog("wayfinder"),c=async()=>{d.bus.send("venueData/loadNavGraph")};let f=new n;d.bus.on("wayfinder/_getNavGraph",()=>f),d.bus.on("venueData/navGraphLoaded",async({navGraphData:t,structures:n})=>{const e=o(n),i=await m(),a=r(t,e.floorIdToOrdinal,e.floorIdToStructureId,i);f.resolve(a)}),d.bus.on("poi/setDynamicRouting",async({idValuesMap:t})=>{const n=await f,o=Object.values(t).filter(t=>t.position&&void 0!==t.position.floorId&&t.position.latitude&&t.position.longitude).map(t=>n.findClosestNode(t.position.floorId,t.position.latitude,t.position.longitude).id);n.addNodesToAvoid(o)});const m=async()=>{const n=await d.bus.get("poi/getByCategoryId",{categoryId:"security"});return t.pipe(t.map(y),t.filter(t.identity))(n)},y=n=>n.queue&&{type:t.path(["queue","queueType"],n),id:t.path(["queue","queueSubtype"],n)};d.bus.on("wayfinder/showNavLineFromPhysicalLocation",async({toEndpoint:t,selectedSecurityLanes:n=null,requiresAccessibility:o})=>async function(t,n,o){const e=await T({fromEndpoint:t,toEndpoint:n,options:o});if(e){const{segments:t}=e;o.primary&&d.bus.send("map/resetNavlineFeatures"),d.bus.send("map/showNavlineFeatures",{segments:t,category:o.primary?"primary":"alternative"})}return e}(await d.bus.getFirst("user/getPhysicalLocation"),t,{selectedSecurityLanes:n,requiresAccessibility:o,primary:!0}));const g=(t,n)=>d.bus.get("poi/getById",{id:t}).then(o=>{if(o&&o.position)return w(o,n);throw Error("Unknown POI ID "+t)});const h=["lat","lng","floorId","ordinal"],I=t.pipe(t.pick(h),t.keys,t.propEq(h.length,"length"),Boolean),w=(t,n)=>({lat:t.position.latitude,lng:t.position.longitude,floorId:t.position.floorId,ordinal:n(t.position.floorId),title:t.name});async function T({fromEndpoint:t,toEndpoint:n,options:o={}}){const e=await d.bus.get("poi/getAll")||{},r=Array.isArray(e)?e[0]:e,a=Object.values(r).filter(t=>t.category&&t.category.startsWith("security")),u=await d.bus.getFirst("directions/getPreferredUnits")||"meters";return f.then(async e=>{o.compareFindPaths=l.compareFindPaths;const r=i(e,t,n,o);if(!r)return null;const c=await d.bus.get("venueData/getFloorIdToNameMap"),f=await d.bus.get("venueData/getQueueTypes"),m=d.gt(),y=o.requiresAccessibility,{steps:g,segments:h}=s(r.waypoints,t,n,c,m,f,y,a,u);p.info("route",r);const I=Math.round(r.waypoints.reduce((t,{eta:n})=>t+n,0)),w=Math.round(r.waypoints.reduce((t,{distance:n})=>t+n,0));return{...r,segments:h,steps:g,time:I,distance:w}})}function b(n,o,e,i){let r=t.clone(n);return r=E(r,e,i),o&&o.length?{...r,transitTime:v(o,"transitTime"),distance:v(o,"distance")}:(r.distance="start"===i?O(r,e):O(e,r),r.transitTime=S(r.distance),r)}function v(n,o){return t.aperture(2,n).map(([n,o])=>{return(e=o.id,n=>t.find(t=>t.dst===e,n.edges))(n);var e}).map(t.prop(o)).reduce((t,n)=>t+n,0)}function E(t,n,o){return{...t,[o+"Information"]:{lat:n?.lat||n?.position?.latitude,lng:n?.lng||n?.position?.longitude,floorId:n?.floorId||n?.position?.floorId}}}function O(t,n){return e(n?.lat||n?.position?.latitude,n?.lng||n?.position?.longitude,t?.lat||t?.position?.latitude,t?.lng||t?.position?.longitude)}function S(t){return t/60}function L(n){const o=n.filter(t=>null!==t);return t.sortBy(t.propOr(1/0,"transitTime"),o)}function N(t,n){return t&&t.length?v(t,"transitTime"):S(n)}function P(t,n,o){return t&&t.length?v(t,"distance"):O(o,n)}return d.bus.on("wayfinder/getNavigationEndpoint",({ep:t})=>async function(t){return f.then(n=>{if(!t)throw Error("wayfinder: Invalid endpoint definition",t);if("number"==typeof t)return g(t,n.floorIdToOrdinal);if("string"==typeof t){if(t.match(/^\d+$/))return g(parseInt(t),n.floorIdToOrdinal);if(t.indexOf(",")>0){const[o,e,i,r]=t.split(",");if(!n.floorIdToStructureId(i))throw Error("Unknown floorId in endpoint: "+i);let a=r;return a||(a="Starting Point"),{lat:parseFloat(o),lng:parseFloat(e),ordinal:n.floorIdToOrdinal(i),floorId:i,title:a}}}if(I(t))return t;if(t.latitude)return{lat:t.latitude,lng:t.longitude,floorId:t.floorId,ordinal:n.floorIdToOrdinal(t.floorId),title:t.title};if(t.position&&t.name)return w(t,n.floorIdToOrdinal);throw Error("Invalid start or end point: "+t)})}(t)),d.bus.on("wayfinder/checkIfPathHasSecurity",({fromEndpoint:n,toEndpoint:o,options:e={}})=>f.then(r=>{e.compareFindPaths=l.compareFindPaths;const a=i(r,n,o,e);if(!a)return{routeExists:!1};const s=n=>Boolean(a.waypoints.find(t.pathEq(n,["securityLane","type"])));return{routeExists:!0,queues:a.waypoints.filter(n=>t.pathEq(u.SECURITY,["securityLane","type"],n)||t.pathEq(u.IMMIGRATION,["securityLane","type"],n)),hasSecurity:s(u.SECURITY),hasImmigration:s(u.IMMIGRATION)}})),d.bus.on("wayfinder/getRoute",T),d.bus.on("wayfinder/addPathTimeMultiple",async({pois:n,startLocation:o,options:e={}})=>o?f.then(i=>function(n,o,e,i){try{const r=t.clone(e),a=r.map(t=>w(t,n.floorIdToOrdinal)),s=n.findAllShortestPaths(i,a,o);return L(r.map((t,n)=>b(t,s[n],i,"start")))}catch(t){return p.error(t),e}}(i,e,n,o)):n),d.bus.on("wayfinder/multipointAddPathTimeMultiple",async({pois:n,startLocation:o,endLocation:e,currentLocation:i,options:r={}})=>o||e||i?f.then(a=>function(n,o,e,i,r,a){try{const s=i?w(i,n.floorIdToOrdinal):a,u=r?w(r,n.floorIdToOrdinal):null,d=t.clone(e),l=d.map(t=>w(t,n.floorIdToOrdinal));let p,c,f;return s&&(p=n.findAllShortestPaths(s,l,o)),u&&(c=function(t,n,o,e){const i=[];for(const r of n)i.push(t.findShortestPath(r,o,e));return i}(n,l,u,o)),f=s&&u?d.map((n,o)=>function(n,o,e,i,r){const a=P(o,i,n),s=P(e,n,r);if(!a||!s)return null;const u=N(o,a),d=N(e,s);let l=t.clone(n);return l=E(l,i,"start"),l=E(l,r,"end"),{...l,transitTime:u+d,distance:a+s,startInformation:{...l.startInformation,transitTime:u,distance:a},endInformation:{...l.endInformation,transitTime:d,distance:s}}}(n,p[o],c[o],s,u)):s?d.map((t,n)=>b(t,p[n],s,"start")):d.map((t,n)=>b(t,c[n],u,"end")),L(f)}catch(t){return p.error(t),e}}(a,r,n,o,e,i)):n),d.bus.on("venueData/loadNewVenue",()=>{f=new n,c()}),d.bus.on("poi/setDynamicData",({plugin:t,idValuesMap:n})=>{"security"===t&&f.then(t=>t.updateWithSecurityWaitTime(n))}),d.bus.on("wayfinder/getNavGraphFeatures",()=>f.then(({_nodes:t})=>a(t))),{init:c,internal:{resolveNavGraph:t=>f.resolve(t),prepareSecurityLanes:m}}}export{u as SecurityLaneType,d as create};
@@ -1 +1 @@
1
- import{getFloor as o,getStructureAndFloorAtPoint as t,getStructureForFloorId as n}from"./geom.js";async function r(r,l){if(l.poiId)return r.bus.get("wayfinder/getNavigationEndpoint",{ep:l.poiId});let{lat:a,lng:e,ord:u,ordinal:d,floorId:s,title:f="",structureId:c}=l;if(null==a||null==e)throw Error("To obtain a location, you must provide a lat,lng or a poiId");void 0===d&&void 0!==u&&(d=u);const g=await i(r);if(null==d){if(null==s)throw Error("Call to locationToEndpoint with no ordinal and no floorId");{const t=o(g,s);if(!t)throw Error(`floor with id ${s} not found.`);d=t.ordinal}}else if(null==s){const o=await r.bus.get("map/getViewBBox"),{structure:n,floor:i}=t(g,a,e,d,o,!0);s=i?.id,c=n?.id}return null!=s&&null==c&&(c=n(g,s)?.id),{lat:a,lng:e,floorId:s,ordinal:d,title:f,structureId:c}}const i=async o=>o.bus.get("venueData/getVenueData").then(o=>o.structures);export{i as getStructures,r as locationToEndpoint};
1
+ import{getFloor as o,getStructureAndFloorAtPoint as t,getStructureForFloorId as n}from"./geom.js";async function r(r,l){if(l.poiId)return r.bus.get("wayfinder/getNavigationEndpoint",{ep:l.poiId});const{lat:a,lng:e,ord:u,title:d=""}=l;let{ordinal:s,floorId:f,structureId:c}=l;if(null==a||null==e)throw Error("To obtain a location, you must provide a lat,lng or a poiId");void 0===s&&void 0!==u&&(s=u);const g=await i(r);if(null==s){if(null==f)throw Error("Call to locationToEndpoint with no ordinal and no floorId");{const t=o(g,f);if(!t)throw Error(`floor with id ${f} not found.`);s=t.ordinal}}else if(null==f){const o=await r.bus.get("map/getViewBBox"),{structure:n,floor:i}=t(g,a,e,s,o,!0);f=i?.id,c=n?.id}return null!=f&&null==c&&(c=n(g,f)?.id),{lat:a,lng:e,floorId:f,ordinal:s,title:d,structureId:c}}const i=async o=>o.bus.get("venueData/getVenueData").then(o=>o.structures);export{i as getStructures,r as locationToEndpoint};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atriusmaps-node-sdk",
3
- "version": "3.3.892",
3
+ "version": "3.3.894",
4
4
  "description": "This project provides an API to Atrius Personal Wayfinder maps within a Node environment. See the README.md for more information",
5
5
  "keywords": [
6
6
  "map",