incyclist-services 1.4.22 → 1.4.24

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.
@@ -36,6 +36,7 @@ export interface ActivityAppLink {
36
36
  export type ActivityAppLinks = {
37
37
  strava?: ActivityAppLink;
38
38
  velohero?: ActivityAppLink;
39
+ intervals?: ActivityAppLink;
39
40
  };
40
41
  export type ScreenShotInfo = {
41
42
  fileName: string;
@@ -847,37 +847,37 @@ let ActivityRideService = (() => {
847
847
  this.current.tsUpdate = tsNow;
848
848
  }
849
849
  getTotalDistance() {
850
- var _a, _b, _c, _d;
850
+ var _a, _b, _c, _d, _e, _f;
851
851
  const route = this.current.route;
852
852
  if (!route)
853
853
  return 0;
854
854
  const isLoop = (0, route_1.checkIsLoop)(route);
855
- const totalRouteDistance = this.current.endPos !== undefined && !isLoop ? this.current.endPos : (_a = route.points[route.points.length - 1]) === null || _a === void 0 ? void 0 : _a.routeDistance;
855
+ const totalRouteDistance = (_b = (_a = this.current) === null || _a === void 0 ? void 0 : _a.endPos) !== null && _b !== void 0 ? _b : (_c = route.points[route.points.length - 1]) === null || _c === void 0 ? void 0 : _c.routeDistance;
856
856
  if (isLoop) {
857
- const currentLap = Math.floor(((_b = this.current.routeDistance) !== null && _b !== void 0 ? _b : 0) / totalRouteDistance);
858
- return totalRouteDistance - ((_c = this.activity.startPos) !== null && _c !== void 0 ? _c : 0) + currentLap * totalRouteDistance;
857
+ const currentLap = Math.floor(((_d = this.current.routeDistance) !== null && _d !== void 0 ? _d : 0) / totalRouteDistance);
858
+ return totalRouteDistance - ((_e = this.activity.startPos) !== null && _e !== void 0 ? _e : 0) + currentLap * totalRouteDistance;
859
859
  }
860
860
  else {
861
- return totalRouteDistance - ((_d = this.activity.startPos) !== null && _d !== void 0 ? _d : 0);
861
+ return totalRouteDistance - ((_f = this.activity.startPos) !== null && _f !== void 0 ? _f : 0);
862
862
  }
863
863
  }
864
864
  getTotalElevation() {
865
- var _a, _b, _c, _d;
865
+ var _a, _b, _c, _d, _e, _f, _g;
866
866
  const route = this.current.route;
867
867
  if (!route)
868
868
  return 0;
869
869
  const isLoop = (0, route_1.checkIsLoop)(route);
870
- const totalRouteDistance = this.current.endPos !== undefined && !isLoop ? this.current.endPos : (_a = route.points[route.points.length - 1]) === null || _a === void 0 ? void 0 : _a.routeDistance;
871
- let totalElevation = (_b = route.points[route.points.length - 1]) === null || _b === void 0 ? void 0 : _b.elevationGain;
872
- if (this.current.endPos !== undefined && !isLoop) {
870
+ const totalRouteDistance = (_b = (_a = this.current) === null || _a === void 0 ? void 0 : _a.endPos) !== null && _b !== void 0 ? _b : (_c = route.points[route.points.length - 1]) === null || _c === void 0 ? void 0 : _c.routeDistance;
871
+ let totalElevation = (_d = route.points[route.points.length - 1]) === null || _d === void 0 ? void 0 : _d.elevationGain;
872
+ if (((_e = this.current) === null || _e === void 0 ? void 0 : _e.endPos) !== undefined) {
873
873
  const endPosPoint = route.points.find(p => p.routeDistance >= this.current.endPos);
874
874
  if (endPosPoint) {
875
875
  totalElevation = endPosPoint.elevationGain;
876
876
  }
877
877
  }
878
- const gainAtStart = (0, route_1.getElevationGainAt)(route, (_c = this.activity.startPos) !== null && _c !== void 0 ? _c : 0);
878
+ const gainAtStart = (0, route_1.getElevationGainAt)(route, (_f = this.activity.startPos) !== null && _f !== void 0 ? _f : 0);
879
879
  if (isLoop) {
880
- const currentLap = Math.floor(((_d = this.current.routeDistance) !== null && _d !== void 0 ? _d : 0) / totalRouteDistance);
880
+ const currentLap = Math.floor(((_g = this.current.routeDistance) !== null && _g !== void 0 ? _g : 0) / totalRouteDistance);
881
881
  return totalElevation - gainAtStart + currentLap * totalElevation;
882
882
  }
883
883
  else {
@@ -1,4 +1,5 @@
1
1
  export * from './velohero';
2
2
  export * from './strava';
3
+ export * from './intervals';
3
4
  export * from './types';
4
5
  export * from './factory';
@@ -16,5 +16,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./velohero"), exports);
18
18
  __exportStar(require("./strava"), exports);
19
+ __exportStar(require("./intervals"), exports);
19
20
  __exportStar(require("./types"), exports);
20
21
  __exportStar(require("./factory"), exports);
@@ -0,0 +1,18 @@
1
+ import { IncyclistService } from "../../base/service";
2
+ import { ActivityDetails } from "../base";
3
+ import { IActivityUpload } from "./types";
4
+ import { IntervalsAppConnection } from "../../apps/intervals/IntervalsAppConnection";
5
+ import { IntervalsFormat } from "../../apps";
6
+ export declare class IntervalsUpload extends IncyclistService implements IActivityUpload {
7
+ protected isInitialized: any;
8
+ protected connection: IntervalsAppConnection;
9
+ constructor();
10
+ init(): boolean;
11
+ isConnected(): boolean;
12
+ upload(activity: ActivityDetails, format?: string): Promise<boolean>;
13
+ getUrl(activityId: string): string;
14
+ protected getIntervalsFormat(format: string): IntervalsFormat;
15
+ protected ensureInitialized(): any;
16
+ protected getIntervalsAppConnection(): IntervalsAppConnection;
17
+ protected getApi(): import("../../apps").IntervalsApi;
18
+ }
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
3
+ var useValue = arguments.length > 2;
4
+ for (var i = 0; i < initializers.length; i++) {
5
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
6
+ }
7
+ return useValue ? value : void 0;
8
+ };
9
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
10
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
11
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
12
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
13
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
14
+ var _, done = false;
15
+ for (var i = decorators.length - 1; i >= 0; i--) {
16
+ var context = {};
17
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
18
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
19
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
20
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
21
+ if (kind === "accessor") {
22
+ if (result === void 0) continue;
23
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
24
+ if (_ = accept(result.get)) descriptor.get = _;
25
+ if (_ = accept(result.set)) descriptor.set = _;
26
+ if (_ = accept(result.init)) initializers.unshift(_);
27
+ }
28
+ else if (_ = accept(result)) {
29
+ if (kind === "field") initializers.unshift(_);
30
+ else descriptor[key] = _;
31
+ }
32
+ }
33
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
34
+ done = true;
35
+ };
36
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
37
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
+ return new (P || (P = Promise))(function (resolve, reject) {
39
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
40
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
41
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
42
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
43
+ });
44
+ };
45
+ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
46
+ if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
47
+ return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.IntervalsUpload = void 0;
51
+ const service_1 = require("../../base/service");
52
+ const types_1 = require("../../base/types");
53
+ const Injection_1 = require("../../base/decorators/Injection");
54
+ const factory_1 = require("./factory");
55
+ const IntervalsAppConnection_1 = require("../../apps/intervals/IntervalsAppConnection");
56
+ let IntervalsUpload = (() => {
57
+ let _classDecorators = [types_1.Singleton];
58
+ let _classDescriptor;
59
+ let _classExtraInitializers = [];
60
+ let _classThis;
61
+ let _classSuper = service_1.IncyclistService;
62
+ let _instanceExtraInitializers = [];
63
+ let _getIntervalsAppConnection_decorators;
64
+ var IntervalsUpload = _classThis = class extends _classSuper {
65
+ constructor() {
66
+ super('IntervalsUpload');
67
+ this.isInitialized = __runInitializers(this, _instanceExtraInitializers);
68
+ this.connection = new IntervalsAppConnection_1.IntervalsAppConnection();
69
+ this.isInitialized = false;
70
+ this.init();
71
+ }
72
+ init() {
73
+ if (this.isInitialized)
74
+ return true;
75
+ this.isInitialized = this.getIntervalsAppConnection().init();
76
+ return this.isInitialized;
77
+ }
78
+ isConnected() {
79
+ return this.getIntervalsAppConnection().isConnected();
80
+ }
81
+ upload(activity_1) {
82
+ return __awaiter(this, arguments, void 0, function* (activity, format = 'TCX') {
83
+ try {
84
+ const ok = this.ensureInitialized();
85
+ if (!ok) {
86
+ this.logEvent({ message: 'Intervals.icu Upload skipped', reason: 'not initialized' });
87
+ return false;
88
+ }
89
+ if (!this.isConnected())
90
+ return false;
91
+ const lcFormat = format.toLowerCase();
92
+ const ucFormat = format.toUpperCase();
93
+ this.logEvent({ message: 'Intervals.icu Upload', format: ucFormat });
94
+ if (!activity.links)
95
+ activity.links = {};
96
+ const fileName = activity[`${lcFormat}FileName`];
97
+ const res = yield this.getApi().upload(fileName, {
98
+ name: activity.title,
99
+ description: '',
100
+ format: this.getIntervalsFormat(format)
101
+ });
102
+ this.logEvent({ message: 'Intervals.icu Upload success', activityId: res.intervalsId });
103
+ activity.links.intervals = {
104
+ activity_id: res.intervalsId,
105
+ url: this.getUrl(res.intervalsId)
106
+ };
107
+ return true;
108
+ }
109
+ catch (err) {
110
+ this.logEvent({ message: 'Intervals.icu Upload failure', error: err.message });
111
+ activity.links.intervals = {
112
+ error: err.message
113
+ };
114
+ return false;
115
+ }
116
+ });
117
+ }
118
+ getUrl(activityId) {
119
+ return `https://intervals.icu/activities/${activityId}`;
120
+ }
121
+ getIntervalsFormat(format) {
122
+ switch (format.toLowerCase()) {
123
+ case 'tcx':
124
+ return 'tcx';
125
+ case 'fit':
126
+ return 'fit';
127
+ case 'gox':
128
+ return 'gpx';
129
+ default:
130
+ return null;
131
+ }
132
+ }
133
+ ensureInitialized() {
134
+ if (!this.isInitialized)
135
+ this.init();
136
+ return this.isInitialized;
137
+ }
138
+ getIntervalsAppConnection() {
139
+ return this.connection;
140
+ }
141
+ getApi() {
142
+ return this.getIntervalsAppConnection().getApi();
143
+ }
144
+ };
145
+ __setFunctionName(_classThis, "IntervalsUpload");
146
+ (() => {
147
+ var _a;
148
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_a = _classSuper[Symbol.metadata]) !== null && _a !== void 0 ? _a : null) : void 0;
149
+ _getIntervalsAppConnection_decorators = [Injection_1.Injectable];
150
+ __esDecorate(_classThis, null, _getIntervalsAppConnection_decorators, { kind: "method", name: "getIntervalsAppConnection", static: false, private: false, access: { has: obj => "getIntervalsAppConnection" in obj, get: obj => obj.getIntervalsAppConnection }, metadata: _metadata }, null, _instanceExtraInitializers);
151
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
152
+ IntervalsUpload = _classThis = _classDescriptor.value;
153
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
154
+ __runInitializers(_classThis, _classExtraInitializers);
155
+ })();
156
+ return IntervalsUpload = _classThis;
157
+ })();
158
+ exports.IntervalsUpload = IntervalsUpload;
159
+ const factory = new factory_1.ActivityUploadFactory();
160
+ factory.add('intervals', new IntervalsUpload());
@@ -0,0 +1,18 @@
1
+ import { IncyclistService } from "../../base/service";
2
+ import { ActivityDetails } from "../base";
3
+ import { StravaFormat } from "../../apps/base/api/strava";
4
+ import { IActivityUpload } from "./types";
5
+ import { StravaAppConnection } from "../../apps/strava/StravaAppConnection";
6
+ export declare class StravaUpload extends IncyclistService implements IActivityUpload {
7
+ protected isInitialized: any;
8
+ protected connection: StravaAppConnection;
9
+ constructor();
10
+ init(): boolean;
11
+ isConnected(): boolean;
12
+ upload(activity: ActivityDetails, format?: string): Promise<boolean>;
13
+ getUrl(activityId: string): string;
14
+ protected getStravaFormat(format: string): StravaFormat;
15
+ protected ensureInitialized(): any;
16
+ protected getStravaAppConnection(): StravaAppConnection;
17
+ protected getApi(): import("../../apps/base/api/strava").StravaApi;
18
+ }
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
3
+ var useValue = arguments.length > 2;
4
+ for (var i = 0; i < initializers.length; i++) {
5
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
6
+ }
7
+ return useValue ? value : void 0;
8
+ };
9
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
10
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
11
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
12
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
13
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
14
+ var _, done = false;
15
+ for (var i = decorators.length - 1; i >= 0; i--) {
16
+ var context = {};
17
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
18
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
19
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
20
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
21
+ if (kind === "accessor") {
22
+ if (result === void 0) continue;
23
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
24
+ if (_ = accept(result.get)) descriptor.get = _;
25
+ if (_ = accept(result.set)) descriptor.set = _;
26
+ if (_ = accept(result.init)) initializers.unshift(_);
27
+ }
28
+ else if (_ = accept(result)) {
29
+ if (kind === "field") initializers.unshift(_);
30
+ else descriptor[key] = _;
31
+ }
32
+ }
33
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
34
+ done = true;
35
+ };
36
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
37
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
+ return new (P || (P = Promise))(function (resolve, reject) {
39
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
40
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
41
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
42
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
43
+ });
44
+ };
45
+ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
46
+ if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
47
+ return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.StravaUpload = void 0;
51
+ const service_1 = require("../../base/service");
52
+ const types_1 = require("../../base/types");
53
+ const strava_1 = require("../../apps/base/api/strava");
54
+ const Injection_1 = require("../../base/decorators/Injection");
55
+ const factory_1 = require("./factory");
56
+ const StravaAppConnection_1 = require("../../apps/strava/StravaAppConnection");
57
+ let StravaUpload = (() => {
58
+ let _classDecorators = [types_1.Singleton];
59
+ let _classDescriptor;
60
+ let _classExtraInitializers = [];
61
+ let _classThis;
62
+ let _classSuper = service_1.IncyclistService;
63
+ let _instanceExtraInitializers = [];
64
+ let _getStravaAppConnection_decorators;
65
+ var StravaUpload = _classThis = class extends _classSuper {
66
+ constructor() {
67
+ super('StravaUpload');
68
+ this.isInitialized = __runInitializers(this, _instanceExtraInitializers);
69
+ this.connection = new StravaAppConnection_1.StravaAppConnection();
70
+ this.isInitialized = false;
71
+ this.init();
72
+ }
73
+ init() {
74
+ if (this.isInitialized)
75
+ return true;
76
+ this.isInitialized = this.getStravaAppConnection().init();
77
+ return this.isInitialized;
78
+ }
79
+ isConnected() {
80
+ return this.getStravaAppConnection().isConnected();
81
+ }
82
+ upload(activity_1) {
83
+ return __awaiter(this, arguments, void 0, function* (activity, format = 'TCX') {
84
+ try {
85
+ const ok = this.ensureInitialized();
86
+ if (!ok) {
87
+ this.logEvent({ message: 'Strava Upload skipped', reason: 'not initialized' });
88
+ return false;
89
+ }
90
+ if (!this.isConnected())
91
+ return false;
92
+ const lcFormat = format.toLowerCase();
93
+ const ucFormat = format.toUpperCase();
94
+ this.logEvent({ message: 'Strava Upload', format: ucFormat });
95
+ if (!activity.links)
96
+ activity.links = {};
97
+ const fileName = activity[`${lcFormat}FileName`];
98
+ const res = yield this.getApi().upload(fileName, {
99
+ name: activity.title,
100
+ description: '',
101
+ format: this.getStravaFormat(format)
102
+ });
103
+ this.logEvent({ message: 'Strava Upload success', activityId: res.stravaId });
104
+ activity.links.strava = {
105
+ activity_id: res.stravaId,
106
+ url: this.getUrl(res.stravaId)
107
+ };
108
+ return true;
109
+ }
110
+ catch (err) {
111
+ if (err instanceof strava_1.DuplicateError) {
112
+ this.logEvent({ message: 'Strava Upload failure', error: 'duplicate', activityId: err.stravaId });
113
+ activity.links.strava = {
114
+ activity_id: err.stravaId,
115
+ url: this.getUrl(err.stravaId)
116
+ };
117
+ }
118
+ else {
119
+ this.logEvent({ message: 'Strava Upload failure', error: err.message });
120
+ activity.links.strava = {
121
+ error: err.message
122
+ };
123
+ }
124
+ return false;
125
+ }
126
+ });
127
+ }
128
+ getUrl(activityId) {
129
+ return `https://www.strava.com/activities/${activityId}`;
130
+ }
131
+ getStravaFormat(format) {
132
+ switch (format.toLowerCase()) {
133
+ case 'tcx':
134
+ return 'tcx';
135
+ case 'fit':
136
+ return 'fit';
137
+ case 'gox':
138
+ return 'gpx';
139
+ default:
140
+ return null;
141
+ }
142
+ }
143
+ ensureInitialized() {
144
+ if (!this.isInitialized)
145
+ this.init();
146
+ return this.isInitialized;
147
+ }
148
+ getStravaAppConnection() {
149
+ return this.connection;
150
+ }
151
+ getApi() {
152
+ return this.getStravaAppConnection().getApi();
153
+ }
154
+ };
155
+ __setFunctionName(_classThis, "StravaUpload");
156
+ (() => {
157
+ var _a;
158
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_a = _classSuper[Symbol.metadata]) !== null && _a !== void 0 ? _a : null) : void 0;
159
+ _getStravaAppConnection_decorators = [Injection_1.Injectable];
160
+ __esDecorate(_classThis, null, _getStravaAppConnection_decorators, { kind: "method", name: "getStravaAppConnection", static: false, private: false, access: { has: obj => "getStravaAppConnection" in obj, get: obj => obj.getStravaAppConnection }, metadata: _metadata }, null, _instanceExtraInitializers);
161
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
162
+ StravaUpload = _classThis = _classDescriptor.value;
163
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
164
+ __runInitializers(_classThis, _classExtraInitializers);
165
+ })();
166
+ return StravaUpload = _classThis;
167
+ })();
168
+ exports.StravaUpload = StravaUpload;
169
+ const factory = new factory_1.ActivityUploadFactory();
170
+ factory.add('strava', new StravaUpload());
@@ -1,3 +1,4 @@
1
1
  export * from './velohero';
2
2
  export * from './strava';
3
3
  export * from './komoot';
4
+ export * from './intervals';
@@ -17,3 +17,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./velohero"), exports);
18
18
  __exportStar(require("./strava"), exports);
19
19
  __exportStar(require("./komoot"), exports);
20
+ __exportStar(require("./intervals"), exports);
@@ -0,0 +1,21 @@
1
+ import { Observer } from "../../../../base/types/observer";
2
+ import { AppApiBase } from "../base";
3
+ import { EventLogger } from 'gd-eventlog';
4
+ import { AxiosResponse } from "axios";
5
+ import { IntervalsAthlete, IntervalsConfig, IntervalsUploadProps, IntervalsUploadRequest, IntervalsUploadResult } from "./types";
6
+ export declare class IntervalsApi extends AppApiBase {
7
+ protected config: IntervalsConfig;
8
+ protected logger: EventLogger;
9
+ protected observer: Observer;
10
+ constructor();
11
+ init(config: IntervalsConfig): Observer;
12
+ update(config: Partial<IntervalsConfig>): void;
13
+ isAuthenticated(): boolean;
14
+ upload(fileName: string, props?: IntervalsUploadProps): Promise<IntervalsUploadResult>;
15
+ getLoggedInAthlete(): Promise<IntervalsAthlete>;
16
+ protected verifyAuthentication(): Promise<void>;
17
+ protected createUpload(request: IntervalsUploadRequest): Promise<IntervalsUploadResult>;
18
+ protected get(url: string, config?: object): Promise<AxiosResponse>;
19
+ protected getUploadParams(request: IntervalsUploadRequest): string;
20
+ protected getBaseUrl(): any;
21
+ }
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.IntervalsApi = void 0;
13
+ const observer_1 = require("../../../../base/types/observer");
14
+ const valid_1 = require("../../../../utils/valid");
15
+ const base_1 = require("../base");
16
+ const gd_eventlog_1 = require("gd-eventlog");
17
+ const API_BASE_URL = 'https://intervals.icu/api/v1';
18
+ class IntervalsApi extends base_1.AppApiBase {
19
+ constructor() {
20
+ super();
21
+ this.logger = new gd_eventlog_1.EventLogger('IntervalsApi');
22
+ this.observer = new observer_1.Observer();
23
+ }
24
+ init(config) {
25
+ this.config = config;
26
+ return this.observer;
27
+ }
28
+ update(config) {
29
+ if (!this.config)
30
+ throw new Error('update not allowed before init');
31
+ this.config = Object.assign(Object.assign({}, this.config), config);
32
+ }
33
+ isAuthenticated() {
34
+ var _a;
35
+ return (0, valid_1.valid)((_a = this.config) === null || _a === void 0 ? void 0 : _a.accessToken);
36
+ }
37
+ upload(fileName, props) {
38
+ return __awaiter(this, void 0, void 0, function* () {
39
+ yield this.verifyAuthentication();
40
+ const request = {
41
+ file: { type: 'file', fileName },
42
+ name: props === null || props === void 0 ? void 0 : props.name,
43
+ description: props === null || props === void 0 ? void 0 : props.description,
44
+ externalId: props.externalId
45
+ };
46
+ return yield this.createUpload(request);
47
+ });
48
+ }
49
+ getLoggedInAthlete() {
50
+ return __awaiter(this, void 0, void 0, function* () {
51
+ var _a;
52
+ const response = yield this.get('/athlete/0/profile');
53
+ return (_a = response.data) === null || _a === void 0 ? void 0 : _a.athlete;
54
+ });
55
+ }
56
+ verifyAuthentication() {
57
+ return __awaiter(this, void 0, void 0, function* () {
58
+ if (!this.isAuthenticated())
59
+ throw new Error('not authenticated');
60
+ });
61
+ }
62
+ createUpload(request) {
63
+ return __awaiter(this, void 0, void 0, function* () {
64
+ var _a, _b, _c, _d, _e, _f, _g, _h;
65
+ const reqOpts = {
66
+ headers: {
67
+ Authorization: 'Bearer ' + this.config.accessToken
68
+ }
69
+ };
70
+ let url = `/athlete/0/activities${this.getUploadParams(request)}`;
71
+ const form = yield this.createForm(url, { file: request.file }, reqOpts);
72
+ const response = yield this.postForm(form);
73
+ if (response.data && !response.error && !response.data.error) {
74
+ const result = response.data;
75
+ return {
76
+ externalId: request.externalId,
77
+ intervalsId: result.id
78
+ };
79
+ }
80
+ else {
81
+ const result = response.data;
82
+ if (result === null || result === void 0 ? void 0 : result.error)
83
+ throw new Error(result.error);
84
+ throw new Error((_h = (_g = (_d = (_c = (_b = (_a = response.error) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.error) !== null && _d !== void 0 ? _d : (_f = (_e = response.error) === null || _e === void 0 ? void 0 : _e.response) === null || _f === void 0 ? void 0 : _f.message) !== null && _g !== void 0 ? _g : response.error.message) !== null && _h !== void 0 ? _h : `HTTP error ${response.status}`);
85
+ }
86
+ });
87
+ }
88
+ get(url, config) {
89
+ return __awaiter(this, void 0, void 0, function* () {
90
+ const props = config !== null && config !== void 0 ? config : {};
91
+ const request = Object.assign({ method: 'get', url: this.getBaseUrl() + url, headers: {
92
+ Authorization: 'Bearer ' + this.config.accessToken
93
+ } }, props);
94
+ const response = yield this.getApi().request(request);
95
+ return response;
96
+ });
97
+ }
98
+ getUploadParams(request) {
99
+ const params = [];
100
+ if (request.name)
101
+ params.push(`name=${request.name}`);
102
+ if (request.description)
103
+ params.push(`description=${request.description}`);
104
+ if (params.length === 0)
105
+ return '';
106
+ return '?' + params.join('&');
107
+ }
108
+ getBaseUrl() {
109
+ try {
110
+ return this.getUserSettings().get('INTERVALS_API', API_BASE_URL);
111
+ }
112
+ catch (_a) {
113
+ return API_BASE_URL;
114
+ }
115
+ }
116
+ }
117
+ exports.IntervalsApi = IntervalsApi;
@@ -0,0 +1,2 @@
1
+ export * from './types';
2
+ export * from './api';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./types"), exports);
18
+ __exportStar(require("./api"), exports);
@@ -0,0 +1,49 @@
1
+ export type IntervalsConfig = {
2
+ accessToken: string;
3
+ };
4
+ export type IntervalsUploadRequest = {
5
+ file: any;
6
+ name: string;
7
+ description: string;
8
+ externalId?: string;
9
+ };
10
+ export type IntervalsUploadProps = {
11
+ format: IntervalsFormat;
12
+ name?: string;
13
+ description?: string;
14
+ externalId?: string;
15
+ };
16
+ export type IntervalsActivity = {
17
+ icu_athlete_id: string;
18
+ id: string;
19
+ };
20
+ export type IntervalsUploadResponse = {
21
+ icu_athlete_id?: string;
22
+ id?: string;
23
+ status?: number;
24
+ error?: string;
25
+ activities?: IntervalsActivity[];
26
+ };
27
+ export type IntervalsUploadResult = {
28
+ intervalsId?: string;
29
+ externalId?: string;
30
+ };
31
+ export type IntervalsAthleteResult = {
32
+ athlete: IntervalsAthlete;
33
+ sharedFolders: any;
34
+ customItems: any;
35
+ };
36
+ export type IntervalsAthlete = {
37
+ id: string;
38
+ name: string;
39
+ profile_medium: string;
40
+ city: string;
41
+ state: string;
42
+ country: string;
43
+ timezone: string;
44
+ sex: string;
45
+ bio: string;
46
+ website: string;
47
+ email: string;
48
+ };
49
+ export type IntervalsFormat = 'fit' | 'fit.gz' | 'tcx' | 'tcx.gz' | 'gpx' | 'gpx.gz';
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,23 @@
1
+ import { IntervalsApi, IntervalsConfig } from "../base/api";
2
+ import { ConnectedAppService } from "../base/app";
3
+ import { IntervalsCredentials } from "./types";
4
+ export declare class IntervalsAppConnection extends ConnectedAppService<IntervalsCredentials> {
5
+ protected config: IntervalsConfig;
6
+ protected api: IntervalsApi;
7
+ constructor();
8
+ connect(credentials: IntervalsCredentials): Promise<boolean>;
9
+ isConnecting(): boolean;
10
+ disconnect(): void;
11
+ isConnected(): boolean;
12
+ getCredentials(): IntervalsCredentials;
13
+ getApi(): IntervalsApi;
14
+ protected initAuth(): boolean;
15
+ protected updateConfig(config: IntervalsConfig): void;
16
+ protected saveCredentials(config?: IntervalsConfig): void;
17
+ protected getSecret(key: string): string;
18
+ protected buildConfigFromCredentials(credentials: IntervalsCredentials): {
19
+ accessToken: string;
20
+ };
21
+ protected initApi(config: IntervalsConfig): void;
22
+ protected getSecretBindings(): import("../../api/bindings/secret").ISecretBinding;
23
+ }
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
3
+ var useValue = arguments.length > 2;
4
+ for (var i = 0; i < initializers.length; i++) {
5
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
6
+ }
7
+ return useValue ? value : void 0;
8
+ };
9
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
10
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
11
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
12
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
13
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
14
+ var _, done = false;
15
+ for (var i = decorators.length - 1; i >= 0; i--) {
16
+ var context = {};
17
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
18
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
19
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
20
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
21
+ if (kind === "accessor") {
22
+ if (result === void 0) continue;
23
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
24
+ if (_ = accept(result.get)) descriptor.get = _;
25
+ if (_ = accept(result.set)) descriptor.set = _;
26
+ if (_ = accept(result.init)) initializers.unshift(_);
27
+ }
28
+ else if (_ = accept(result)) {
29
+ if (kind === "field") initializers.unshift(_);
30
+ else descriptor[key] = _;
31
+ }
32
+ }
33
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
34
+ done = true;
35
+ };
36
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
37
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
+ return new (P || (P = Promise))(function (resolve, reject) {
39
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
40
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
41
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
42
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
43
+ });
44
+ };
45
+ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
46
+ if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
47
+ return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.IntervalsAppConnection = void 0;
51
+ const api_1 = require("../../api");
52
+ const decorators_1 = require("../../base/decorators");
53
+ const valid_1 = require("../../utils/valid");
54
+ const api_2 = require("../base/api");
55
+ const app_1 = require("../base/app");
56
+ let IntervalsAppConnection = (() => {
57
+ let _classDecorators = [decorators_1.Singleton];
58
+ let _classDescriptor;
59
+ let _classExtraInitializers = [];
60
+ let _classThis;
61
+ let _classSuper = app_1.ConnectedAppService;
62
+ let _instanceExtraInitializers = [];
63
+ let _getSecretBindings_decorators;
64
+ var IntervalsAppConnection = _classThis = class extends _classSuper {
65
+ constructor() {
66
+ super('IntervalsAppConnection', 'intervals');
67
+ this.config = __runInitializers(this, _instanceExtraInitializers);
68
+ }
69
+ connect(credentials) {
70
+ return __awaiter(this, void 0, void 0, function* () {
71
+ this.ensureInitialized();
72
+ this.logEvent({ message: 'Connect with Intervals.icu' });
73
+ try {
74
+ const isConnected = this.isConnected();
75
+ const config = this.buildConfigFromCredentials(credentials);
76
+ if (isConnected) {
77
+ this.getApi().update(config);
78
+ }
79
+ else {
80
+ this.initApi(config);
81
+ this.saveCredentials(config);
82
+ }
83
+ this.logEvent({ message: 'Connect with Intervals.icu success' });
84
+ return true;
85
+ }
86
+ catch (err) {
87
+ this.logError(err, 'connect');
88
+ throw err;
89
+ }
90
+ });
91
+ }
92
+ isConnecting() {
93
+ return false;
94
+ }
95
+ disconnect() {
96
+ try {
97
+ this.config = undefined;
98
+ this.saveCredentials();
99
+ this.getApi().init(undefined);
100
+ }
101
+ catch (err) {
102
+ this.logError(err, 'disconnect');
103
+ }
104
+ }
105
+ isConnected() {
106
+ if (!this.isInitialized) {
107
+ this.init();
108
+ }
109
+ if (this.getApi().isAuthenticated() && !this.config) {
110
+ this.initAuth();
111
+ }
112
+ return ((0, valid_1.valid)(this.config));
113
+ }
114
+ getCredentials() {
115
+ const userSettings = this.getUserSettings();
116
+ try {
117
+ return userSettings.get('user.auth.intervals', null);
118
+ }
119
+ catch (_a) {
120
+ return null;
121
+ }
122
+ }
123
+ getApi() {
124
+ if (!this.api)
125
+ this.api = new api_2.IntervalsApi();
126
+ return this.api;
127
+ }
128
+ initAuth() {
129
+ let isInitialized = false;
130
+ try {
131
+ const auth = this.getCredentials();
132
+ if (auth) {
133
+ this.logEvent({ message: 'Intervals.icu init done', hasCredentials: true });
134
+ this.config = this.buildConfigFromCredentials(auth);
135
+ this.initApi(this.config);
136
+ }
137
+ else {
138
+ this.logEvent({ message: 'Intervals.icu init done', hasCredentials: false });
139
+ }
140
+ isInitialized = true;
141
+ }
142
+ catch (err) {
143
+ this.logEvent({ message: 'error', error: err.message, fn: 'init', stack: err.stack });
144
+ isInitialized = false;
145
+ delete this.config;
146
+ }
147
+ return isInitialized;
148
+ }
149
+ updateConfig(config) {
150
+ const { accessToken } = config;
151
+ this.config = Object.assign(Object.assign({}, this.config), { accessToken });
152
+ this.saveCredentials();
153
+ }
154
+ saveCredentials(config) {
155
+ if (config)
156
+ this.config = config;
157
+ try {
158
+ if (!this.isConnected()) {
159
+ this.logEvent({ message: 'Intervals.icu Delete Credentials' });
160
+ this.getUserSettings().set('user.auth.intervals', null);
161
+ return;
162
+ }
163
+ this.logEvent({ message: 'Intervals.icu Save Credentials' });
164
+ this.getUserSettings().set('user.auth.intervals', {
165
+ accesstoken: this.config.accessToken
166
+ });
167
+ }
168
+ catch (err) {
169
+ this.logEvent({ message: 'error', fn: 'saveCredentials', error: err.message, stack: err.stack });
170
+ }
171
+ this.logEvent({ message: 'Intervals.icu Save Credentials done' });
172
+ }
173
+ getSecret(key) {
174
+ var _a;
175
+ return (_a = this.getSecretBindings()) === null || _a === void 0 ? void 0 : _a.getSecret(key);
176
+ }
177
+ buildConfigFromCredentials(credentials) {
178
+ return {
179
+ accessToken: credentials === null || credentials === void 0 ? void 0 : credentials.accesstoken
180
+ };
181
+ }
182
+ initApi(config) {
183
+ this.getApi().init(config);
184
+ }
185
+ getSecretBindings() {
186
+ var _a;
187
+ return (_a = (0, api_1.getBindings)()) === null || _a === void 0 ? void 0 : _a.secret;
188
+ }
189
+ };
190
+ __setFunctionName(_classThis, "IntervalsAppConnection");
191
+ (() => {
192
+ var _a;
193
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_a = _classSuper[Symbol.metadata]) !== null && _a !== void 0 ? _a : null) : void 0;
194
+ _getSecretBindings_decorators = [decorators_1.Injectable];
195
+ __esDecorate(_classThis, null, _getSecretBindings_decorators, { kind: "method", name: "getSecretBindings", static: false, private: false, access: { has: obj => "getSecretBindings" in obj, get: obj => obj.getSecretBindings }, metadata: _metadata }, null, _instanceExtraInitializers);
196
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
197
+ IntervalsAppConnection = _classThis = _classDescriptor.value;
198
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
199
+ __runInitializers(_classThis, _classExtraInitializers);
200
+ })();
201
+ return IntervalsAppConnection = _classThis;
202
+ })();
203
+ exports.IntervalsAppConnection = IntervalsAppConnection;
@@ -0,0 +1,28 @@
1
+ import { StravaApi, StravaConfig } from "../base/api";
2
+ import { ConnectedAppService } from "../base/app";
3
+ import { StravaCredentials } from "./types";
4
+ export declare class StravaAppConnection extends ConnectedAppService<StravaCredentials> {
5
+ protected config: StravaConfig;
6
+ protected api: StravaApi;
7
+ protected tokenUpdateHandler: any;
8
+ constructor();
9
+ connect(credentials: StravaCredentials): Promise<boolean>;
10
+ isConnecting(): boolean;
11
+ disconnect(): void;
12
+ isConnected(): boolean;
13
+ getCredentials(): StravaCredentials;
14
+ getApi(): StravaApi;
15
+ protected initAuth(): boolean;
16
+ protected updateConfig(config: StravaConfig): void;
17
+ protected saveCredentials(config?: StravaConfig): void;
18
+ protected getSecret(key: string): string;
19
+ protected buildConfigFromCredentials(credentials: StravaCredentials): {
20
+ clientId: string;
21
+ clientSecret: string;
22
+ accessToken: any;
23
+ refreshToken: any;
24
+ expiration: Date;
25
+ };
26
+ protected initApi(config: StravaConfig): void;
27
+ protected getSecretBindings(): import("../../api/bindings/secret").ISecretBinding;
28
+ }
@@ -0,0 +1,211 @@
1
+ "use strict";
2
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
3
+ var useValue = arguments.length > 2;
4
+ for (var i = 0; i < initializers.length; i++) {
5
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
6
+ }
7
+ return useValue ? value : void 0;
8
+ };
9
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
10
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
11
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
12
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
13
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
14
+ var _, done = false;
15
+ for (var i = decorators.length - 1; i >= 0; i--) {
16
+ var context = {};
17
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
18
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
19
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
20
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
21
+ if (kind === "accessor") {
22
+ if (result === void 0) continue;
23
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
24
+ if (_ = accept(result.get)) descriptor.get = _;
25
+ if (_ = accept(result.set)) descriptor.set = _;
26
+ if (_ = accept(result.init)) initializers.unshift(_);
27
+ }
28
+ else if (_ = accept(result)) {
29
+ if (kind === "field") initializers.unshift(_);
30
+ else descriptor[key] = _;
31
+ }
32
+ }
33
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
34
+ done = true;
35
+ };
36
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
37
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
38
+ return new (P || (P = Promise))(function (resolve, reject) {
39
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
40
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
41
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
42
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
43
+ });
44
+ };
45
+ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
46
+ if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
47
+ return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.StravaAppConnection = void 0;
51
+ const api_1 = require("../../api");
52
+ const decorators_1 = require("../../base/decorators");
53
+ const valid_1 = require("../../utils/valid");
54
+ const api_2 = require("../base/api");
55
+ const app_1 = require("../base/app");
56
+ let StravaAppConnection = (() => {
57
+ let _classDecorators = [decorators_1.Singleton];
58
+ let _classDescriptor;
59
+ let _classExtraInitializers = [];
60
+ let _classThis;
61
+ let _classSuper = app_1.ConnectedAppService;
62
+ let _instanceExtraInitializers = [];
63
+ let _getSecretBindings_decorators;
64
+ var StravaAppConnection = _classThis = class extends _classSuper {
65
+ constructor() {
66
+ super('StravaAppConnection', 'strava');
67
+ this.config = __runInitializers(this, _instanceExtraInitializers);
68
+ this.tokenUpdateHandler = this.updateConfig.bind(this);
69
+ }
70
+ connect(credentials) {
71
+ return __awaiter(this, void 0, void 0, function* () {
72
+ this.ensureInitialized();
73
+ this.logEvent({ message: 'Connect with Strava' });
74
+ try {
75
+ const isConnected = this.isConnected();
76
+ const config = this.buildConfigFromCredentials(credentials);
77
+ if (isConnected) {
78
+ this.getApi().update(config);
79
+ }
80
+ else {
81
+ this.initApi(config);
82
+ this.saveCredentials(config);
83
+ }
84
+ this.logEvent({ message: 'Connect with Strava success' });
85
+ return true;
86
+ }
87
+ catch (err) {
88
+ this.logError(err, 'connect');
89
+ throw err;
90
+ }
91
+ });
92
+ }
93
+ isConnecting() {
94
+ return false;
95
+ }
96
+ disconnect() {
97
+ try {
98
+ this.config = undefined;
99
+ this.saveCredentials();
100
+ this.getApi().init(undefined);
101
+ }
102
+ catch (err) {
103
+ this.logError(err, 'disconnect');
104
+ }
105
+ }
106
+ isConnected() {
107
+ if (!this.isInitialized) {
108
+ this.init();
109
+ }
110
+ return ((0, valid_1.valid)(this.config));
111
+ }
112
+ getCredentials() {
113
+ const userSettings = this.getUserSettings();
114
+ try {
115
+ return userSettings.get('user.auth.strava', null);
116
+ }
117
+ catch (_a) {
118
+ return null;
119
+ }
120
+ }
121
+ getApi() {
122
+ if (!this.api)
123
+ this.api = new api_2.StravaApi();
124
+ return this.api;
125
+ }
126
+ initAuth() {
127
+ let isInitialized = false;
128
+ try {
129
+ const auth = this.getCredentials();
130
+ const clientId = this.getSecret('STRAVA_CLIENT_ID');
131
+ const clientSecret = this.getSecret('STRAVA_CLIENT_SECRET');
132
+ if (clientId && clientSecret && auth) {
133
+ this.logEvent({ message: 'Strava init done', hasCredentials: true });
134
+ this.config = this.buildConfigFromCredentials(auth);
135
+ this.initApi(this.config);
136
+ }
137
+ else {
138
+ this.logEvent({ message: 'Strava init done', hasCredentials: false });
139
+ }
140
+ isInitialized = true;
141
+ }
142
+ catch (err) {
143
+ this.logEvent({ message: 'error', error: err.message, fn: 'init', stack: err.stack });
144
+ isInitialized = false;
145
+ delete this.config;
146
+ }
147
+ return isInitialized;
148
+ }
149
+ updateConfig(config) {
150
+ const { accessToken, refreshToken, expiration } = config;
151
+ this.config = Object.assign(Object.assign({}, this.config), { accessToken, refreshToken, expiration });
152
+ this.saveCredentials();
153
+ }
154
+ saveCredentials(config) {
155
+ var _a;
156
+ if (config)
157
+ this.config = config;
158
+ try {
159
+ if (!this.isConnected()) {
160
+ this.logEvent({ message: 'Strava Delete Credentials' });
161
+ this.getUserSettings().set('user.auth.strava', null);
162
+ return;
163
+ }
164
+ this.logEvent({ message: 'Strava Save Credentials' });
165
+ this.getUserSettings().set('user.auth.strava', {
166
+ accesstoken: this.config.accessToken,
167
+ refreshtoken: this.config.refreshToken,
168
+ expiration: (_a = this.config.expiration) === null || _a === void 0 ? void 0 : _a.toISOString()
169
+ });
170
+ }
171
+ catch (err) {
172
+ this.logEvent({ message: 'error', fn: 'saveCredentials', error: err.message, stack: err.stack });
173
+ }
174
+ this.logEvent({ message: 'Strava Save Credentials done' });
175
+ }
176
+ getSecret(key) {
177
+ var _a;
178
+ return (_a = this.getSecretBindings()) === null || _a === void 0 ? void 0 : _a.getSecret(key);
179
+ }
180
+ buildConfigFromCredentials(credentials) {
181
+ return {
182
+ clientId: this.getSecret('STRAVA_CLIENT_ID'),
183
+ clientSecret: this.getSecret('STRAVA_CLIENT_SECRET'),
184
+ accessToken: credentials === null || credentials === void 0 ? void 0 : credentials.accesstoken,
185
+ refreshToken: credentials === null || credentials === void 0 ? void 0 : credentials.refreshtoken,
186
+ expiration: (credentials === null || credentials === void 0 ? void 0 : credentials.expiration) ? new Date(credentials.expiration) : undefined
187
+ };
188
+ }
189
+ initApi(config) {
190
+ const observer = this.getApi().init(config);
191
+ observer.on('token.updated', this.tokenUpdateHandler);
192
+ }
193
+ getSecretBindings() {
194
+ var _a;
195
+ return (_a = (0, api_1.getBindings)()) === null || _a === void 0 ? void 0 : _a.secret;
196
+ }
197
+ };
198
+ __setFunctionName(_classThis, "StravaAppConnection");
199
+ (() => {
200
+ var _a;
201
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_a = _classSuper[Symbol.metadata]) !== null && _a !== void 0 ? _a : null) : void 0;
202
+ _getSecretBindings_decorators = [decorators_1.Injectable];
203
+ __esDecorate(_classThis, null, _getSecretBindings_decorators, { kind: "method", name: "getSecretBindings", static: false, private: false, access: { has: obj => "getSecretBindings" in obj, get: obj => obj.getSecretBindings }, metadata: _metadata }, null, _instanceExtraInitializers);
204
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
205
+ StravaAppConnection = _classThis = _classDescriptor.value;
206
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
207
+ __runInitializers(_classThis, _classExtraInitializers);
208
+ })();
209
+ return StravaAppConnection = _classThis;
210
+ })();
211
+ exports.StravaAppConnection = StravaAppConnection;
File without changes
File without changes
@@ -0,0 +1,6 @@
1
+ import { AppCredentials } from "../base/types";
2
+ export interface IntervalsCredentials extends AppCredentials {
3
+ accesstoken: string;
4
+ refreshtoken: string;
5
+ expiration?: string;
6
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -54,6 +54,7 @@ const service_1 = require("../base/service");
54
54
  const types_1 = require("../base/types");
55
55
  const settings_1 = require("../settings");
56
56
  const base_1 = require("./base");
57
+ const IntervalsAppConnection_1 = require("./intervals/IntervalsAppConnection");
57
58
  const komoot_1 = require("./komoot");
58
59
  const VeloHeroAppConnection_1 = require("./velohero/VeloHeroAppConnection");
59
60
  let AppsService = (() => {
@@ -69,7 +70,7 @@ let AppsService = (() => {
69
70
  constructor() {
70
71
  super('AppsService');
71
72
  this.services = (__runInitializers(this, _instanceExtraInitializers), {
72
- ActivityUpload: ['strava', 'velohero', 'intervals.icu'],
73
+ ActivityUpload: ['strava', 'velohero', 'intervals'],
73
74
  WorkoutUpload: [],
74
75
  WorkoutDownload: [],
75
76
  ActivityDownload: [],
@@ -79,6 +80,7 @@ let AppsService = (() => {
79
80
  { name: 'Strava', key: 'strava', iconUrl: 'https://static.cdnlogo.com/logos/s/42/strava-wordmark.svg', connection: new base_1.StravaAppConnection() },
80
81
  { name: 'VeloHero', key: 'velohero', iconUrl: 'images/velo-white.png', connection: new VeloHeroAppConnection_1.VeloHeroAppConnection() },
81
82
  { name: 'Komoot', key: 'komoot', iconUrl: 'https://www.komoot.com/assets/4d8ae313eec53e6e.svg', connection: new komoot_1.KomootAppConnection() },
83
+ { name: 'Intervals.icu', key: 'intervals', iconUrl: 'images/intervals.png', connection: new IntervalsAppConnection_1.IntervalsAppConnection() },
82
84
  ];
83
85
  }
84
86
  openSettings() {
@@ -96,8 +96,9 @@ const getReferencedFileInfo = (info, referenced, scheme = 'file') => {
96
96
  };
97
97
  exports.getReferencedFileInfo = getReferencedFileInfo;
98
98
  const buildFromFile = (info, referenced, scheme = 'file') => {
99
+ var _a;
99
100
  if (referenced.file) {
100
- const fileName = info.filename.replace(info.name, referenced.file);
101
+ const fileName = (_a = info.filename) === null || _a === void 0 ? void 0 : _a.replace(info.name, referenced.file);
101
102
  return `file:///${fileName}`;
102
103
  }
103
104
  return referenced.url;
@@ -247,6 +247,8 @@ class XMLParser {
247
247
  prevTime = 0;
248
248
  }
249
249
  else {
250
+ if (mapping.frame == prev.frame || mapping.distance === prev.distance)
251
+ return;
250
252
  const time = addMapping(mapping, prev, idx, startFrame, prevTime);
251
253
  prevTime = time;
252
254
  }
@@ -275,6 +277,11 @@ class XMLParser {
275
277
  routeDistance: Number(a.distance),
276
278
  elevation: Number(a.height),
277
279
  }));
280
+ route.points = route.points.filter((p, idx) => {
281
+ if (idx === 0)
282
+ return true;
283
+ return (p.routeDistance !== route.points[idx - 1].routeDistance);
284
+ });
278
285
  const points = route.points;
279
286
  if ((points === null || points === void 0 ? void 0 : points.length) > 0) {
280
287
  route.distance = points[points.length - 1].routeDistance;
@@ -294,6 +301,13 @@ class XMLParser {
294
301
  route.elevation = 0;
295
302
  const points = [];
296
303
  positions.forEach((pos, i) => {
304
+ if (i > 0) {
305
+ const prev = positions[i - 1];
306
+ if (prev.distance === pos.distance) {
307
+ console.log('# found duplicate position');
308
+ return;
309
+ }
310
+ }
297
311
  const altitude = getAltitude(altitudes, positions, i, prevAltitude);
298
312
  const elevationGain = altitude - prevAltitude;
299
313
  const pi = createPoint(pos, altitude, prevDistance);
@@ -1050,7 +1050,9 @@ let RouteListService = (() => {
1050
1050
  }
1051
1051
  }
1052
1052
  resetCards() {
1053
- this.getLists().forEach(list => {
1053
+ var _a;
1054
+ const lists = (_a = this.getLists()) !== null && _a !== void 0 ? _a : [];
1055
+ lists.forEach(list => {
1054
1056
  list.getCards().forEach((card) => {
1055
1057
  card.reset(true);
1056
1058
  });
@@ -403,9 +403,9 @@ let WorkoutRide = (() => {
403
403
  const ftp = this.settings.ftp;
404
404
  const wo = this.workout;
405
405
  const limits = wo.getLimits(time, true);
406
- this.currentStep = limits.step;
407
- const request = { time: 0, duration: 0, remaining: 0 };
408
406
  if (limits !== undefined) {
407
+ this.currentStep = limits.step;
408
+ const request = { time: 0, duration: 0, remaining: 0 };
409
409
  request.time = Math.round(time);
410
410
  request.minPower = this.getPowerVal(limits.power, 'min');
411
411
  request.maxPower = this.getPowerVal(limits.power, 'max');
@@ -415,7 +415,7 @@ let WorkoutRide = (() => {
415
415
  request.maxHrm = ((_d = limits.hrm) === null || _d === void 0 ? void 0 : _d.max) ? Math.round(limits.hrm.max) : undefined;
416
416
  this.currentLimits = Object.assign(Object.assign({}, request), { duration: limits.duration, remaining: limits.remaining });
417
417
  }
418
- this.isFreeRide = limits.power === undefined || limits.power === null;
418
+ this.isFreeRide = (limits === null || limits === void 0 ? void 0 : limits.power) === undefined || (limits === null || limits === void 0 ? void 0 : limits.power) === null;
419
419
  this.logger.logEvent(Object.assign(Object.assign({ message: 'workout requests' }, this.currentLimits), { ftp }));
420
420
  this.emit('request-update', this.currentLimits);
421
421
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "incyclist-services",
3
- "version": "1.4.22",
3
+ "version": "1.4.24",
4
4
  "peerDependencies": {
5
5
  "gd-eventlog": "^0.1.26"
6
6
  },