incyclist-services 1.7.46 → 1.7.48

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 (34) hide show
  1. package/lib/cjs/api/repository/json/index.js +33 -6
  2. package/lib/cjs/apps/service.js +1 -0
  3. package/lib/cjs/maps/MapArea/options.js +29 -22
  4. package/lib/cjs/maps/MapArea/service.js +28 -12
  5. package/lib/cjs/maps/MapArea/utils.js +8 -6
  6. package/lib/cjs/ride/page/service.js +26 -13
  7. package/lib/cjs/ride/route/GpxDisplayService.js +3 -2
  8. package/lib/cjs/ride/route/RouteDisplayService.js +23 -16
  9. package/lib/cjs/routes/download/service.js +4 -5
  10. package/lib/cjs/routes/list/cards/RouteCard.js +6 -7
  11. package/lib/cjs/services/overpass/overpass.js +7 -1
  12. package/lib/esm/api/repository/json/index.js +33 -6
  13. package/lib/esm/apps/service.js +1 -0
  14. package/lib/esm/maps/MapArea/options.js +29 -22
  15. package/lib/esm/maps/MapArea/service.js +29 -13
  16. package/lib/esm/maps/MapArea/utils.js +8 -6
  17. package/lib/esm/ride/page/service.js +26 -13
  18. package/lib/esm/ride/route/GpxDisplayService.js +3 -2
  19. package/lib/esm/ride/route/RouteDisplayService.js +24 -17
  20. package/lib/esm/routes/download/service.js +4 -5
  21. package/lib/esm/routes/list/cards/RouteCard.js +6 -7
  22. package/lib/esm/services/overpass/overpass.js +7 -1
  23. package/lib/types/activities/ride/types.d.ts +16 -0
  24. package/lib/types/api/repository/json/index.d.ts +5 -4
  25. package/lib/types/i18n/units/converter.d.ts +2 -2
  26. package/lib/types/maps/MapArea/options.d.ts +2 -2
  27. package/lib/types/maps/MapArea/service.d.ts +10 -9
  28. package/lib/types/maps/MapArea/types.d.ts +2 -2
  29. package/lib/types/ride/base/types.d.ts +2 -2
  30. package/lib/types/ride/page/service.d.ts +6 -8
  31. package/lib/types/ride/route/GpxDisplayService.d.ts +8 -3
  32. package/lib/types/ride/route/RouteDisplayService.d.ts +19 -15
  33. package/lib/types/services/overpass/overpass.d.ts +7 -3
  34. package/package.json +7 -5
@@ -28,24 +28,45 @@ class JsonRepository {
28
28
  }
29
29
  async write(objectName, data) {
30
30
  await this.open();
31
- const success = await this.access.write(objectName, data);
31
+ if (!this.access)
32
+ return false;
33
+ const success = await this.access.write(this.toFileName(objectName), data);
34
+ if (objectName.includes(':')) {
35
+ await this.access.delete(objectName).catch(() => { });
36
+ }
32
37
  return success;
33
38
  }
34
39
  async read(objectName) {
35
40
  await this.open();
36
- const data = await this.access.read(objectName);
41
+ if (!this.access)
42
+ return;
43
+ const fileName = this.toFileName(objectName);
44
+ let data;
45
+ try {
46
+ data = await this.access.read(fileName);
47
+ }
48
+ catch { }
37
49
  try {
50
+ if (!data && objectName.includes(':')) {
51
+ data = await this.access.read(objectName);
52
+ }
38
53
  const str = JSON.stringify(data);
39
54
  if (str === '{}' || str.length < 2)
40
- return null;
55
+ return;
41
56
  }
42
57
  catch {
43
- return null;
58
+ return;
44
59
  }
45
60
  return data;
46
61
  }
47
62
  async delete(objectName) {
48
- return await this.access.delete(objectName);
63
+ await this.open();
64
+ if (!this.access)
65
+ return false;
66
+ const result = await this.access.delete(this.toFileName(objectName));
67
+ if (objectName.includes(':'))
68
+ await this.access.delete(objectName).catch(() => { });
69
+ return result;
49
70
  }
50
71
  async open() {
51
72
  if (this.access)
@@ -68,6 +89,9 @@ class JsonRepository {
68
89
  }
69
90
  }
70
91
  async list(exclude) {
92
+ await this.open();
93
+ if (!this.access)
94
+ return null;
71
95
  try {
72
96
  let names = await this.access.list();
73
97
  if (!names)
@@ -87,8 +111,11 @@ class JsonRepository {
87
111
  async close() {
88
112
  const db = (0, bindings_1.getBindings)().db;
89
113
  db.release(this.name);
90
- this.access = null;
114
+ delete this.access;
91
115
  return true;
92
116
  }
117
+ toFileName(objectName) {
118
+ return objectName.replaceAll(':', '_');
119
+ }
93
120
  }
94
121
  exports.JsonRepository = JsonRepository;
@@ -103,6 +103,7 @@ let AppsService = (() => {
103
103
  return false;
104
104
  const success = await entry.connection.connect(credentials);
105
105
  this.emit('connected', app, success);
106
+ return success;
106
107
  }
107
108
  isConnected(app) {
108
109
  const entry = this.serviceMap.find(e => e.key === app);
@@ -23,8 +23,8 @@ class OptionManager {
23
23
  }
24
24
  async getStartOptions(way, crossing) {
25
25
  const options = [];
26
- const parts = this.map.splitAtCrossingPoint(way, crossing);
27
- const { segments, points } = this.map.buildSegmentInfo(way, parts);
26
+ const parts = this.map?.splitAtCrossingPoint(way, crossing) ?? [];
27
+ const { segments = [], points = [] } = this.map?.buildSegmentInfo(way, parts) ?? {};
28
28
  for (const segment of segments ?? []) {
29
29
  try {
30
30
  const path = segment.path;
@@ -82,7 +82,7 @@ class OptionManager {
82
82
  }
83
83
  const map = await this.service.load(location);
84
84
  if (!map) {
85
- if (!this.map)
85
+ if (!this.map?.isWithinBoundary(location))
86
86
  return [];
87
87
  }
88
88
  else {
@@ -92,20 +92,21 @@ class OptionManager {
92
92
  const remaining = this.getRemaining(way);
93
93
  let options = [];
94
94
  if (node !== undefined && remaining !== undefined) {
95
- node.ways.forEach((wid) => {
95
+ (node.ways ?? []).forEach((wid) => {
96
96
  if (wid === remaining.id) {
97
97
  options.push(...this.getOptionsOnCurrentWay(node, remaining, options));
98
98
  }
99
99
  else {
100
100
  const w = this.getWay(wid);
101
- options.push(...this.checkOptionsOnDifferentWay(node, w, options));
101
+ if (w)
102
+ options.push(...this.checkOptionsOnDifferentWay(node, w, options));
102
103
  }
103
104
  });
104
105
  }
105
106
  options = (0, utils_1.removeDuplicatePaths)(options);
106
- const currentDirection = this.map.getHeading(way, 'end');
107
+ const currentDirection = this.map?.getHeading(way, 'end') ?? 0;
107
108
  options.forEach((option) => {
108
- const direction = this.map.getHeading(option, 'start');
109
+ const direction = this.map?.getHeading(option, 'start') ?? 0;
109
110
  option.direction = direction - currentDirection;
110
111
  if (option.direction > 180)
111
112
  option.direction = option.direction - 360;
@@ -151,7 +152,7 @@ class OptionManager {
151
152
  }
152
153
  checkOptionsOnDifferentWay(location, w, options) {
153
154
  if (!w?.path || !location)
154
- return;
155
+ return [];
155
156
  let roundabout = (0, utils_1.isRoundabout)(w);
156
157
  if (roundabout)
157
158
  return this.getOptionsRoundabout(location, w, options);
@@ -167,22 +168,24 @@ class OptionManager {
167
168
  return (0, utils_1.removeDuplicates)(options);
168
169
  }
169
170
  getOptionsFirstPoint(location, w, options) {
170
- let result = this.map.splitAtFirstBranch(w);
171
+ let result = this.map?.splitAtFirstBranch(w);
171
172
  let expand = false;
172
- if (result.path.length === w.path.length) {
173
+ if (!result?.path)
174
+ return;
175
+ if (result.path?.length === w.path.length) {
173
176
  const pLast = w.path[w.path.length - 1];
174
- if (pLast.ways.length === 2) {
177
+ if (pLast.ways?.length === 2) {
175
178
  const wIdNext = pLast.ways.find(wid => wid !== w.id);
176
- const wNext = this.getWay(wIdNext);
177
- if (!(0, utils_1.isRoundabout)(wNext)) {
179
+ const wNext = wIdNext ? this.getWay(wIdNext) : undefined;
180
+ if (wNext && !(0, utils_1.isRoundabout)(wNext)) {
178
181
  const pNextStart = wNext.path[0];
179
182
  const pNextEnd = wNext.path[wNext.path.length - 1];
180
183
  if (pNextStart.id === pLast.id) {
181
184
  expand = true;
182
- const segment = this.map.splitAtFirstBranch(wNext);
185
+ const segment = this.map?.splitAtFirstBranch(wNext);
183
186
  const combined = {
184
- id: segment.wayId,
185
- path: w.path.concat(segment.path.slice(1)),
187
+ id: segment?.wayId,
188
+ path: segment?.path ? w.path.concat(segment.path.slice(1)) : w.path,
186
189
  map: this.map
187
190
  };
188
191
  options.push(combined);
@@ -191,10 +194,10 @@ class OptionManager {
191
194
  const wReverse = this.getRemaining(wNext);
192
195
  if (wReverse?.path) {
193
196
  wReverse.path.reverse();
194
- const segment = this.map.splitAtFirstBranch(wNext);
197
+ const segment = this.map?.splitAtFirstBranch(wNext);
195
198
  const combined = {
196
- id: segment.wayId,
197
- path: w.path.concat(segment.path.slice(1)),
199
+ id: segment?.wayId,
200
+ path: segment?.path ? w.path.concat(segment.path.slice(1)) : w.path,
198
201
  map: this.map
199
202
  };
200
203
  options.push(combined);
@@ -302,7 +305,7 @@ class OptionManager {
302
305
  }
303
306
  if (props.id !== undefined) {
304
307
  const map = props.map ?? this.map;
305
- return (0, clone_1.default)(map.getWay(props.id));
308
+ return map ? (0, clone_1.default)(map.getWay(props.id)) : undefined;
306
309
  }
307
310
  }
308
311
  getNode(props) {
@@ -381,6 +384,8 @@ class OptionManager {
381
384
  if (way.path.length > 1) {
382
385
  let prev = way.path[way.path.length - 2];
383
386
  const w = this.getWay(way);
387
+ if (!w)
388
+ return [];
384
389
  if (w.roundabout) {
385
390
  let branches = (0, utils_1.splitAtPoint)(w, location);
386
391
  branches.forEach(b => {
@@ -391,8 +396,10 @@ class OptionManager {
391
396
  });
392
397
  }
393
398
  else if (w.path.length > 1) {
394
- let result = this.map.splitAtFirstBranch(way);
395
- options.push({ id: result.wayId, path: result.path, map: this.map });
399
+ let result = this.map?.splitAtFirstBranch(way);
400
+ if (result) {
401
+ options.push({ id: result.wayId, path: result.path ?? [], map: this.map });
402
+ }
396
403
  }
397
404
  }
398
405
  }
@@ -92,8 +92,7 @@ let MapAreaService = (() => {
92
92
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
93
93
  }
94
94
  static consts = { DEFAULT_RADIUS: consts_1.DEFAULT_RADIUS, DEFAULT_MIN_WAYS: consts_1.DEFAULT_MIN_WAYS, DEFAULT_MAX_WAYS: consts_1.DEFAULT_MAX_WAYS, MAX_DISTANCE_FROM_PATH: consts_1.MAX_DISTANCE_FROM_PATH, GET_WAYS_IN_AREA: consts_1.GET_WAYS_IN_AREA };
95
- overpass = __runInitializers(this, _instanceExtraInitializers);
96
- loaded = 'unknown';
95
+ loaded = (__runInitializers(this, _instanceExtraInitializers), 'unknown');
97
96
  observer;
98
97
  current;
99
98
  minWays;
@@ -103,6 +102,7 @@ let MapAreaService = (() => {
103
102
  maps;
104
103
  optionManager;
105
104
  iv;
105
+ pending = new Map();
106
106
  constructor() {
107
107
  super('MapArea');
108
108
  this.minWays = consts_1.DEFAULT_MIN_WAYS;
@@ -113,21 +113,33 @@ let MapAreaService = (() => {
113
113
  }
114
114
  async load(location) {
115
115
  const map = await this.findBestMap(location);
116
- if (map) {
116
+ if (map)
117
117
  return map;
118
- }
119
- return this.loadMap(location);
118
+ const key = this.mapsKey(location);
119
+ if (this.pending.has(key))
120
+ return this.pending.get(key);
121
+ const promise = this.loadMap(location).finally(() => {
122
+ this.pending.delete(key);
123
+ });
124
+ this.pending.set(key, promise);
125
+ return promise;
120
126
  }
121
127
  getMap(location) {
122
128
  const maps = this.getAllMaps() ?? [];
123
- return maps.find(m => m.isWithinBoundary(location));
129
+ const area = maps.find(m => m.isWithinBoundary(location));
130
+ return area;
124
131
  }
125
132
  getOptionManager() {
126
133
  this.optionManager = this.optionManager ?? new options_1.OptionManager(this);
127
134
  return this.optionManager;
128
135
  }
129
136
  setFilter(filter) {
130
- this.filter = filter ?? undefined;
137
+ if (filter === null) {
138
+ this.filter = [];
139
+ }
140
+ else {
141
+ this.filter = filter;
142
+ }
131
143
  }
132
144
  async findBestMap(location) {
133
145
  if (!this.hasLocationCovered(location))
@@ -140,7 +152,7 @@ let MapAreaService = (() => {
140
152
  if (records.length === 0)
141
153
  break;
142
154
  const record = records.pop();
143
- const { map, radius } = record;
155
+ const { map, radius = consts_1.DEFAULT_RADIUS } = record ?? {};
144
156
  if (!map)
145
157
  continue;
146
158
  const dist = (0, geo_1.distanceBetween)(location, map.getQueryLocation());
@@ -175,9 +187,9 @@ let MapAreaService = (() => {
175
187
  }
176
188
  }
177
189
  }
178
- catch (error) {
190
+ catch (err) {
179
191
  const duration = ts ? Date.now() - ts : undefined;
180
- this.logEvent({ message: 'overpass query result', status: 'failure', error: { code: error.code, response: error.response }, duration });
192
+ this.logEvent({ message: 'overpass query result', status: 'failure', error: { code: err.code, response: err.response }, duration });
181
193
  }
182
194
  await (0, sleep_1.sleep)(1000);
183
195
  }
@@ -251,6 +263,8 @@ let MapAreaService = (() => {
251
263
  this.iv = undefined;
252
264
  }
253
265
  garbageCollection() {
266
+ if (!this.current)
267
+ return;
254
268
  const tsLastUsed = (m) => m.map.getLastUsed() ?? m.lastUsed;
255
269
  const now = Date.now();
256
270
  const maps = Object.values(this.maps).filter(m => now - tsLastUsed(m) < 1000 * 60 * 5);
@@ -263,9 +277,11 @@ let MapAreaService = (() => {
263
277
  }
264
278
  this.logEvent({ message: 'Garbage collection done', cnt: Object.keys(this.maps).length, maps: Object.keys(this.maps).map(k => (0, exports.getMapsInfo)(this.maps, k)) });
265
279
  }
280
+ get overpass() {
281
+ return this.getOverpassAPI();
282
+ }
266
283
  getOverpassAPI() {
267
- this.overpass = this.overpass ?? new overpass_1.OverpassApi();
268
- return this.overpass;
284
+ return (0, overpass_1.useOverpassApi)();
269
285
  }
270
286
  reset() {
271
287
  this.stopGarbageCollection();
@@ -40,13 +40,15 @@ const geo_1 = require("../../utils/geo");
40
40
  const math_1 = require("../../utils/math");
41
41
  const consts_1 = require("./consts");
42
42
  function addNode(node, nodesLookup, id, path) {
43
- let point = nodesLookup[node];
44
- if (point !== undefined)
43
+ const point = nodesLookup[node];
44
+ if (point !== undefined) {
45
45
  path.push(point);
46
- point.ways = point.ways ?? [];
47
- let found = point.ways.find(e => (e.toString() === id.toString()));
48
- if (found === undefined)
49
- nodesLookup[node].ways.push(id.toString());
46
+ point.ways = point.ways ?? [];
47
+ let found = point.ways.find(e => (e.toString() === id.toString()));
48
+ if (!found) {
49
+ point.ways.push(id.toString());
50
+ }
51
+ }
50
52
  }
51
53
  function addWay(w, ways, waysLookup) {
52
54
  if (waysLookup[w.id] !== undefined)
@@ -114,6 +114,7 @@ let RidePageService = (() => {
114
114
  catch (err) {
115
115
  this.logError(err, 'openPage');
116
116
  }
117
+ return this.getPageObserver();
117
118
  }
118
119
  closePage() {
119
120
  try {
@@ -128,7 +129,7 @@ let RidePageService = (() => {
128
129
  this.logError(err, 'closePage');
129
130
  }
130
131
  }
131
- pausePage() {
132
+ async pausePage() {
132
133
  try {
133
134
  this.backgroundTimer = setTimeout(() => {
134
135
  this.getRideDisplay().pause('user');
@@ -141,7 +142,7 @@ let RidePageService = (() => {
141
142
  this.logError(err, 'pausePage');
142
143
  }
143
144
  }
144
- resumePage() {
145
+ async resumePage() {
145
146
  try {
146
147
  if (this.backgroundTimer) {
147
148
  clearTimeout(this.backgroundTimer);
@@ -153,20 +154,28 @@ let RidePageService = (() => {
153
154
  }
154
155
  }
155
156
  getRideObserver() {
156
- return this.rideObserver;
157
+ return this.rideObserver ?? null;
157
158
  }
158
159
  getPageDisplayProps() {
160
+ const startOverlayProps = this.getRideDisplay().getStartOverlayProps();
161
+ const noRideProps = {
162
+ rideState: 'Error',
163
+ startOverlayProps,
164
+ rideType: null,
165
+ menuProps: null,
166
+ startGateProps: null
167
+ };
159
168
  try {
160
169
  const rideType = this.getRideDisplay().getRideType();
161
170
  switch (rideType) {
162
171
  case 'Video': return this.getVideoRideDisplayProps();
163
172
  case 'GPX': return this.getGPXRideDisplayProps();
164
173
  default:
165
- return null;
174
+ return noRideProps;
166
175
  }
167
176
  }
168
- catch (err) {
169
- return null;
177
+ catch {
178
+ return noRideProps;
170
179
  }
171
180
  }
172
181
  onRefreshSecrets() {
@@ -240,12 +249,15 @@ let RidePageService = (() => {
240
249
  this.logError(err, 'onIgnoreStart');
241
250
  }
242
251
  }
243
- async onCancelStart() {
252
+ onCancelStart() {
244
253
  try {
245
254
  this.rideObserver?.stop();
246
- await this.getRideDisplay().cancelStart();
247
- this.moveToPreviousPage();
248
- this.closePage();
255
+ this.getRideDisplay().cancelStart()
256
+ .then(() => {
257
+ this.moveToPreviousPage();
258
+ this.closePage();
259
+ })
260
+ .catch((err) => { this.logError(err, 'onCancelStart'); });
249
261
  }
250
262
  catch (err) {
251
263
  this.logError(err, 'onCancelStart');
@@ -285,8 +297,8 @@ let RidePageService = (() => {
285
297
  return displayProps;
286
298
  }
287
299
  async checkSecretValidity() {
288
- if (this.getBindings().appInfo.getChannel() === 'mobile') {
289
- const secretsStatus = this.getSecretBinding().getSecretsStatus?.();
300
+ if (this.getBindings().appInfo?.getChannel() === 'mobile') {
301
+ const secretsStatus = this.getSecretBinding()?.getSecretsStatus?.();
290
302
  if (secretsStatus === 'stale' || secretsStatus === 'missing' || secretsStatus === undefined) {
291
303
  if (!this.getOnlineStatusMonitoring().onlineStatus)
292
304
  this.showStartGate();
@@ -318,7 +330,7 @@ let RidePageService = (() => {
318
330
  const events = Object.keys(this.eventHandler);
319
331
  events.forEach(event => { this.rideObserver?.off(event, this.eventHandler[event]); });
320
332
  }
321
- onDisplayStateUpdate(state, props) {
333
+ onDisplayStateUpdate(state) {
322
334
  switch (state) {
323
335
  case 'Paused':
324
336
  this.menuProps = { showResume: true };
@@ -342,6 +354,7 @@ let RidePageService = (() => {
342
354
  catch (err) {
343
355
  this.logError(err, 'get rideObserver');
344
356
  }
357
+ return null;
345
358
  }
346
359
  get rideDisplayProps() {
347
360
  return this.getRideDisplay().getDisplayProperties();
@@ -182,7 +182,7 @@ let GpxDisplayService = (() => {
182
182
  }
183
183
  this.emit('state-update');
184
184
  }
185
- onMapViewEvent(state, error) {
185
+ onMapViewEvent(state, _error) {
186
186
  if (state === 'Loaded') {
187
187
  this.mapLoaded = true;
188
188
  }
@@ -300,7 +300,8 @@ let GpxDisplayService = (() => {
300
300
  }
301
301
  return val;
302
302
  }
303
- catch { }
303
+ catch {
304
+ }
304
305
  }
305
306
  isMobile() {
306
307
  return this.getBindings().appInfo?.getChannel() === 'mobile';
@@ -101,9 +101,9 @@ let RouteDisplayService = (() => {
101
101
  return { realityFactor, startPos, route };
102
102
  }
103
103
  onActivityUpdate(activityPos, data) {
104
- if (data.power > 0)
104
+ if ((data.power ?? 0) > 0)
105
105
  this.prevPowerTs = Date.now();
106
- if (data.power === 0 && (data.speed === 0 || data.speed < 5 && (Date.now() - (this.prevPowerTs ?? 0)) > MAX_INACTIVITY)) {
106
+ if (data.power === 0 && (data.speed === 0 || (data.speed ?? 0) < 5 && (Date.now() - (this.prevPowerTs ?? 0)) > MAX_INACTIVITY)) {
107
107
  return;
108
108
  }
109
109
  try {
@@ -130,7 +130,7 @@ let RouteDisplayService = (() => {
130
130
  }
131
131
  super.onActivityUpdate(activityPos, data);
132
132
  }
133
- onPositionUpdate(state) {
133
+ onPositionUpdate(_state) {
134
134
  }
135
135
  onRideSettingsChanged(settings) {
136
136
  try {
@@ -206,24 +206,26 @@ let RouteDisplayService = (() => {
206
206
  const nearbyRides = this.getNearbyRidesProps(props);
207
207
  const [C, U] = this.getUnitConversionShortcuts();
208
208
  const isLoop = this.currentRoute?.description?.isLoop;
209
- const xScale = { value: C(1, 'distance', U('distance')), unit: U('distance') };
210
- const yScale = { value: C(1, 'elevation', U('elevation')), unit: U('elevation') };
209
+ const xScale = { value: C(1, 'distance', { from: U('distance') }), unit: U('distance') };
210
+ const yScale = { value: C(1, 'elevation', { from: U('elevation') }), unit: U('elevation') };
211
211
  const mapStartPos = (isLoop && !loopOverwrite) ? undefined : startPos;
212
212
  return {
213
213
  ...parent,
214
- position: this.position, markers: this.getMarkers(props),
214
+ position: this.position,
215
+ markers: this.getMarkers(props),
215
216
  sideViews: this.sideViews,
216
217
  route: this.getCurrentRoute(),
217
218
  realityFactor,
218
- startPos: mapStartPos, endPos,
219
+ startPos: mapStartPos ?? 0,
220
+ endPos,
219
221
  nearbyRides,
220
222
  xScale, yScale,
221
223
  map, upcomingElevation, totalElevation,
222
224
  };
223
225
  }
224
226
  getScreenshotInfo(fileName, time) {
225
- const { lat, lng, routeDistance, elevation } = this.position;
226
- const position = { lat, lng, routeDistance, elevation };
227
+ const { lat, lng, routeDistance, elevation } = this.position ?? {};
228
+ const position = this.position === undefined ? undefined : { lat, lng, routeDistance, elevation };
227
229
  return { fileName, position, time };
228
230
  }
229
231
  getRoutePosition(distance) {
@@ -237,8 +239,11 @@ let RouteDisplayService = (() => {
237
239
  props = { cnt: 0 };
238
240
  }
239
241
  const pos = (0, routes_1.getPosition)(route, props);
242
+ const totalDistance = route.description?.distance;
243
+ if (!totalDistance)
244
+ return;
240
245
  pos.distance = distance;
241
- pos.lapDistance = pos.routeDistance % route.description.distance;
246
+ pos.lapDistance = pos.routeDistance % totalDistance;
242
247
  pos.heading = (0, routes_1.getHeading)(route, pos);
243
248
  return pos;
244
249
  }
@@ -340,7 +345,12 @@ let RouteDisplayService = (() => {
340
345
  checkIsRouteFinished(position) {
341
346
  if (this.isLoop() && !this.startSettings?.loopOverwrite)
342
347
  return false;
343
- const finished = position.routeDistance >= this.getCurrentRoute().description.distance;
348
+ if (this.startSettings.endPos !== undefined && position.routeDistance > this.startSettings.endPos)
349
+ return true;
350
+ const totalDistance = this.getCurrentRoute().description.distance;
351
+ if (totalDistance === undefined)
352
+ return false;
353
+ const finished = position.routeDistance >= totalDistance;
344
354
  return finished;
345
355
  }
346
356
  onRideFinished() {
@@ -375,7 +385,7 @@ let RouteDisplayService = (() => {
375
385
  this.logError(err, 'cleanupActiveRides');
376
386
  }
377
387
  }
378
- savePosition(startPos) {
388
+ savePosition(_startPos) {
379
389
  }
380
390
  getOriginalRoute() {
381
391
  return this.route;
@@ -399,10 +409,7 @@ let RouteDisplayService = (() => {
399
409
  return (0, api_1.getBindings)().appInfo;
400
410
  }
401
411
  getUnitConversionShortcuts() {
402
- const c = this.getUnitConverter();
403
- const C = c.convert.bind(c);
404
- const U = c.getUnit.bind(c);
405
- return [C, U];
412
+ return (0, i18n_1.getUnitConversionShortcuts)();
406
413
  }
407
414
  getUnitConverter() {
408
415
  return (0, i18n_1.useUnitConverter)();
@@ -135,12 +135,11 @@ let RouteDownloadService = (() => {
135
135
  }
136
136
  waitForVideoDir(observer) {
137
137
  if (this.isMobile()) {
138
+ this.logEvent({ message: 'setting fixed video dir on mobile' });
138
139
  try {
139
- const getVideoDir = this.getBindings()?.downloadManager?.getVideoDir;
140
- if (getVideoDir) {
141
- const videoDir = getVideoDir();
142
- return Promise.resolve(videoDir);
143
- }
140
+ const videoDir = this.getBindings()?.downloadManager?.getVideoDir?.();
141
+ this.logEvent({ message: 'video dir set', videoDir });
142
+ return Promise.resolve(videoDir);
144
143
  }
145
144
  catch { }
146
145
  }
@@ -269,7 +269,7 @@ let RouteCard = (() => {
269
269
  if (points && !Array.isArray(points)) {
270
270
  points = undefined;
271
271
  }
272
- let isNew = (0, utils_2.checkIsNew)(descr);
272
+ const isNew = (0, utils_2.checkIsNew)(descr);
273
273
  const loaded = details !== undefined;
274
274
  const loading = this.deleteObserver !== undefined;
275
275
  const totalDistance = descr.distance === undefined ? undefined : {
@@ -405,12 +405,11 @@ let RouteCard = (() => {
405
405
  value = p;
406
406
  else {
407
407
  const point = p;
408
- value = C(point.routeDistance, 'distance');
408
+ value = C(point.routeDistance, 'distance') ?? 0;
409
409
  }
410
- console.log('# update start pos', p);
411
410
  if (data?.startPos.value === value)
412
411
  return null;
413
- const startPos = { value, unit: U('distance') };
412
+ const startPos = { value, unit: U('distance') ?? 'm' };
414
413
  const updated = { ...data };
415
414
  updated.startPos = startPos;
416
415
  this.adjustStartPosAvi(updated);
@@ -422,12 +421,12 @@ let RouteCard = (() => {
422
421
  const [C, U] = (0, i18n_1.getUnitConversionShortcuts)();
423
422
  const isUI = typeof props.startPos !== 'number';
424
423
  try {
425
- delete props['prevRides'];
424
+ delete props.prevRides;
426
425
  if (isUI) {
427
426
  const uiProps = props;
428
427
  const { realityFactor, segment, showPrev, loopOverwrite, nextOverwrite } = uiProps;
429
- const startPos = C(uiProps.startPos.value, 'distance', { from: U('distance'), to: 'm' });
430
- const endPos = uiProps.endPos === undefined ? uiProps.endPos : C(uiProps.endPos.value, 'distance', { from: U('distance'), to: 'm' });
428
+ const startPos = C(uiProps.startPos.value, 'distance', { from: U('distance'), to: 'm' }) ?? 0;
429
+ const endPos = uiProps.endPos === undefined ? undefined : C(uiProps.endPos.value, 'distance', { from: U('distance'), to: 'm' });
431
430
  this.startSettings = {
432
431
  ...this.startSettings,
433
432
  startPos, endPos, realityFactor, segment, showPrev, loopOverwrite, nextOverwrite
@@ -42,6 +42,7 @@ const promise_any_1 = __importDefault(require("promise.any"));
42
42
  const types_1 = require("../../base/types");
43
43
  const sleep_1 = require("../../utils/sleep");
44
44
  const base_1 = require("../../apps/base/api/base");
45
+ const gd_eventlog_1 = require("gd-eventlog");
45
46
  const OVERPASS_URL_ALT1 = 'https://overpass.kumi.systems/api/interpreter';
46
47
  const OVERPASS_URL_ALT2 = 'https://lz4.overpass-api.de/api/interpreter';
47
48
  const OVERPASS_URL_ALT3 = 'https://z.overpass-api.de/api/interpreter';
@@ -63,10 +64,12 @@ let OverpassApi = (() => {
63
64
  }
64
65
  url;
65
66
  mirrors = [];
67
+ logger;
66
68
  constructor(props) {
67
69
  super();
68
70
  this.mirrors = [OVERPASS_URL_ALT1, OVERPASS_URL_ALT2, OVERPASS_URL_ALT3];
69
71
  this.url = props?.url ?? this.mirrors[0];
72
+ this.logger = new gd_eventlog_1.EventLogger('Overpass');
70
73
  if (props?.url) {
71
74
  if (this.mirrors.indexOf(props.url) === -1) {
72
75
  this.mirrors.push(props.url);
@@ -74,7 +77,10 @@ let OverpassApi = (() => {
74
77
  }
75
78
  }
76
79
  async query(queryOL, timeout) {
77
- return this.bulkQuery(queryOL, timeout);
80
+ this.logger.logEvent({ message: 'query', queryOL, timeout });
81
+ const res = await this.bulkQuery(queryOL, timeout);
82
+ this.logger.logEvent({ message: 'query result', hasData: res !== undefined });
83
+ return res;
78
84
  }
79
85
  async singleQuery(queryOL) {
80
86
  const res = await this.post(this.url, queryOL);