incyclist-services 1.1.102 → 1.2.1

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.
File without changes
File without changes
@@ -0,0 +1,41 @@
1
+ import { EventLogger } from "gd-eventlog";
2
+ import { JsonRepository } from "../../../api";
3
+ import { Observer, PromiseObserver } from "../../../base/types/observer";
4
+ import { ActivityDetails, ActivityInfo, ActivitySummary } from "../model";
5
+ import { ActivitySearchCriteria } from "./types";
6
+ export declare class ActivitiesDbLoader {
7
+ protected repo: JsonRepository;
8
+ protected loadObserver: Observer;
9
+ protected saveObserver: PromiseObserver<void>;
10
+ protected isDirty: boolean;
11
+ protected tsLastWrite: number;
12
+ protected logger: EventLogger;
13
+ protected activities: Array<ActivityInfo>;
14
+ protected isDBComplete: boolean;
15
+ constructor();
16
+ load(): Observer;
17
+ stopLoad(): void;
18
+ save(activity: ActivityInfo, writeDetails?: boolean): Promise<void>;
19
+ delete(activity: ActivityInfo | string): Promise<void>;
20
+ get(id: string): ActivityInfo;
21
+ getWithDetails(id: string): Promise<ActivityInfo>;
22
+ search(criteria: ActivitySearchCriteria): Array<ActivityInfo>;
23
+ protected writeRepo(): Promise<void>;
24
+ protected write(enforce?: boolean): void;
25
+ protected emitDone(): void;
26
+ protected emitUpdated(activity: ActivityInfo | Array<ActivityInfo>): void;
27
+ protected emitAdded(activity: ActivityInfo | Array<ActivityInfo>): void;
28
+ protected loadSummaries(): Promise<void>;
29
+ protected buildFromLegacy(): Promise<void>;
30
+ protected listActivities(): Promise<Array<string>>;
31
+ protected loadDetailsByName(name: string): Promise<ActivityDetails>;
32
+ protected loadDetails(name: string, id?: string): Promise<void>;
33
+ protected writeDetails(activity: ActivityInfo): Promise<void>;
34
+ protected buildSummary(activity: ActivityDetails, name: string): ActivitySummary;
35
+ protected scanForActivities(): Promise<Array<ActivitySummary> | null>;
36
+ protected scanForActivitiesAndMerge(activities: Array<ActivitySummary>): Promise<Array<ActivitySummary>>;
37
+ protected _load(): Promise<void>;
38
+ protected getActivity(id: string): ActivityInfo;
39
+ protected logError(error: Error, fn: string, logProps?: any): void;
40
+ protected getRepo(): JsonRepository;
41
+ }
@@ -0,0 +1,378 @@
1
+ "use strict";
2
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
3
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
4
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
5
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
6
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
7
+ var _, done = false;
8
+ for (var i = decorators.length - 1; i >= 0; i--) {
9
+ var context = {};
10
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
11
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
12
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
13
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
14
+ if (kind === "accessor") {
15
+ if (result === void 0) continue;
16
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
17
+ if (_ = accept(result.get)) descriptor.get = _;
18
+ if (_ = accept(result.set)) descriptor.set = _;
19
+ if (_ = accept(result.init)) initializers.unshift(_);
20
+ }
21
+ else if (_ = accept(result)) {
22
+ if (kind === "field") initializers.unshift(_);
23
+ else descriptor[key] = _;
24
+ }
25
+ }
26
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
27
+ done = true;
28
+ };
29
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
30
+ var useValue = arguments.length > 2;
31
+ for (var i = 0; i < initializers.length; i++) {
32
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
33
+ }
34
+ return useValue ? value : void 0;
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.ActivitiesDbLoader = void 0;
51
+ const gd_eventlog_1 = require("gd-eventlog");
52
+ const api_1 = require("../../../api");
53
+ const types_1 = require("../../../base/types");
54
+ const observer_1 = require("../../../base/types/observer");
55
+ const utils_1 = require("../../../utils");
56
+ const DB_VERSION = '1';
57
+ let ActivitiesDbLoader = (() => {
58
+ let _classDecorators = [types_1.Singleton];
59
+ let _classDescriptor;
60
+ let _classExtraInitializers = [];
61
+ let _classThis;
62
+ var ActivitiesDbLoader = _classThis = class {
63
+ constructor() {
64
+ this.logger = new gd_eventlog_1.EventLogger('ActivitiesDB');
65
+ }
66
+ load() {
67
+ if (this.loadObserver)
68
+ return this.loadObserver;
69
+ this.loadObserver = new observer_1.Observer();
70
+ this._load();
71
+ return this.loadObserver;
72
+ }
73
+ stopLoad() {
74
+ this.emitDone();
75
+ }
76
+ save(activity, writeDetails = true) {
77
+ return __awaiter(this, void 0, void 0, function* () {
78
+ const stringify = (json) => { try {
79
+ JSON.stringify(json);
80
+ }
81
+ catch (_a) { } };
82
+ let prev;
83
+ const idx = this.activities.findIndex(ai => ai.summary.id === activity.summary.id);
84
+ if (idx === -1) {
85
+ this.activities.push(activity);
86
+ }
87
+ else {
88
+ prev = stringify(this.activities[idx]);
89
+ this.activities[idx] = activity;
90
+ }
91
+ const changed = !prev || stringify(activity) !== prev;
92
+ if (changed) {
93
+ this.isDirty = true;
94
+ this.write();
95
+ if (writeDetails) {
96
+ this.writeDetails(activity);
97
+ }
98
+ }
99
+ });
100
+ }
101
+ delete(activity) {
102
+ return __awaiter(this, void 0, void 0, function* () {
103
+ let target = activity;
104
+ if (typeof (activity) === 'string') {
105
+ target = this.getActivity(activity);
106
+ }
107
+ if (!target)
108
+ return;
109
+ const id = target.summary.id;
110
+ const idx = this.activities.findIndex(ai => ai.summary.id === id);
111
+ if (idx) {
112
+ this.activities.splice(idx, 1);
113
+ this.write(true);
114
+ }
115
+ const name = target.summary.name;
116
+ yield this.getRepo().delete(name);
117
+ });
118
+ }
119
+ get(id) {
120
+ const info = this.getActivity(id);
121
+ if (!info)
122
+ return;
123
+ return info;
124
+ }
125
+ getWithDetails(id) {
126
+ return __awaiter(this, void 0, void 0, function* () {
127
+ const info = this.getActivity(id);
128
+ if (!info)
129
+ return;
130
+ if (!info.details) {
131
+ yield this.loadDetails(info.summary.name, id);
132
+ }
133
+ return info;
134
+ });
135
+ }
136
+ search(criteria) {
137
+ let result = this.activities;
138
+ if ((result === null || result === void 0 ? void 0 : result.length) > 0 && (criteria === null || criteria === void 0 ? void 0 : criteria.routeId)) {
139
+ result = result.filter(ai => ai.summary.routeId === criteria.routeId);
140
+ }
141
+ if ((result === null || result === void 0 ? void 0 : result.length) > 0 && (criteria === null || criteria === void 0 ? void 0 : criteria.startPos) !== undefined) {
142
+ result = result.filter(ai => ai.summary.startPos === criteria.startPos);
143
+ }
144
+ if ((result === null || result === void 0 ? void 0 : result.length) > 0 && (criteria === null || criteria === void 0 ? void 0 : criteria.realityFactor) !== undefined) {
145
+ result = result.filter(ai => { var _a; return ((_a = ai.summary.realityFactor) !== null && _a !== void 0 ? _a : 100) === criteria.realityFactor; });
146
+ }
147
+ if ((result === null || result === void 0 ? void 0 : result.length) > 0 && (criteria === null || criteria === void 0 ? void 0 : criteria.isSaved) !== undefined) {
148
+ result = result.filter(ai => ai.summary.isSaved === criteria.isSaved);
149
+ }
150
+ if ((result === null || result === void 0 ? void 0 : result.length) > 0 && (criteria === null || criteria === void 0 ? void 0 : criteria.uploadStatus) !== undefined) {
151
+ if (Array.isArray(criteria.uploadStatus)) {
152
+ result = result.filter(ai => {
153
+ const requested = criteria.uploadStatus;
154
+ const actual = ai.summary.uploadStatus;
155
+ const r = requested.sort().map(us => `${us.service}:${us.status}`).join(';');
156
+ const a = actual.sort().map(us => `${us.service}:${us.status}`).join(';');
157
+ return r === a;
158
+ });
159
+ }
160
+ else {
161
+ const status = criteria.uploadStatus;
162
+ result = result.filter(ai => {
163
+ const serviceInfo = ai.summary.uploadStatus.find(asi => asi.service === status.service);
164
+ if (!serviceInfo)
165
+ return false;
166
+ return serviceInfo.status === status.status;
167
+ });
168
+ }
169
+ }
170
+ return result;
171
+ }
172
+ writeRepo() {
173
+ return __awaiter(this, void 0, void 0, function* () {
174
+ if (this.saveObserver)
175
+ yield this.saveObserver.wait();
176
+ const save = () => __awaiter(this, void 0, void 0, function* () {
177
+ const isComplete = this.isDBComplete;
178
+ try {
179
+ const dbData = {
180
+ version: DB_VERSION,
181
+ isComplete,
182
+ activties: this.activities.map(ai => ai.summary)
183
+ };
184
+ yield this.getRepo().write('db', dbData);
185
+ }
186
+ catch (err) {
187
+ this.logger.logEvent({ message: 'could not safe repo', error: err.message });
188
+ }
189
+ });
190
+ this.saveObserver = new observer_1.PromiseObserver(save());
191
+ yield this.saveObserver.start();
192
+ process.nextTick(() => { delete this.saveObserver; });
193
+ });
194
+ }
195
+ write(enforce = false) {
196
+ if (enforce)
197
+ this.isDirty = true;
198
+ if (this.isDirty && (this.tsLastWrite === undefined || Date.now() - this.tsLastWrite >= 1000)) {
199
+ this.isDirty = false;
200
+ this.tsLastWrite = Date.now();
201
+ this.writeRepo();
202
+ }
203
+ if (this.isDirty && Date.now() - this.tsLastWrite < 1000) {
204
+ setTimeout(() => { this.write(); }, this.tsLastWrite + 1000 - Date.now());
205
+ }
206
+ }
207
+ emitDone() {
208
+ if (this.loadObserver)
209
+ this.loadObserver.emit('done');
210
+ (0, utils_1.waitNextTick)().then(() => {
211
+ this.loadObserver.reset();
212
+ delete this.loadObserver;
213
+ });
214
+ }
215
+ emitUpdated(activity) {
216
+ if (this.loadObserver)
217
+ this.loadObserver.emit('updated', activity);
218
+ }
219
+ emitAdded(activity) {
220
+ if (this.loadObserver)
221
+ this.loadObserver.emit('added', activity);
222
+ }
223
+ loadSummaries() {
224
+ return __awaiter(this, void 0, void 0, function* () {
225
+ const dbData = yield this.getRepo().read('db');
226
+ if (dbData) {
227
+ const { activities, isComplete } = dbData;
228
+ this.activities = activities.map(summary => ({ summary }));
229
+ this.emitAdded(this.activities);
230
+ this.isDBComplete = isComplete;
231
+ if (!isComplete) {
232
+ const cnt = activities.length;
233
+ const update = yield this.scanForActivitiesAndMerge(activities);
234
+ if (cnt !== update.length) {
235
+ yield this.write(true);
236
+ }
237
+ return;
238
+ }
239
+ }
240
+ yield this.buildFromLegacy();
241
+ return;
242
+ });
243
+ }
244
+ buildFromLegacy() {
245
+ return __awaiter(this, void 0, void 0, function* () {
246
+ const activities = yield this.scanForActivities();
247
+ if (activities !== null) {
248
+ this.activities = activities.map(summary => ({ summary }));
249
+ }
250
+ yield this.write(true);
251
+ });
252
+ }
253
+ listActivities() {
254
+ return __awaiter(this, void 0, void 0, function* () {
255
+ return this.getRepo().list();
256
+ });
257
+ }
258
+ loadDetailsByName(name) {
259
+ return __awaiter(this, void 0, void 0, function* () {
260
+ let details;
261
+ try {
262
+ details = yield this.getRepo().read(name);
263
+ }
264
+ catch (err) {
265
+ this.logger.logEvent({ message: 'could not load activity details', name, reason: err.message, stack: err.stack });
266
+ }
267
+ return details;
268
+ });
269
+ }
270
+ loadDetails(name, id) {
271
+ return __awaiter(this, void 0, void 0, function* () {
272
+ const details = yield this.loadDetailsByName(name);
273
+ const aid = id !== null && id !== void 0 ? id : details.id;
274
+ const activity = this.getActivity(aid);
275
+ if (activity) {
276
+ activity.details = details;
277
+ this.emitUpdated(activity);
278
+ }
279
+ });
280
+ }
281
+ writeDetails(activity) {
282
+ return __awaiter(this, void 0, void 0, function* () {
283
+ const name = activity.summary.name;
284
+ this.getRepo().write(name, activity.details);
285
+ });
286
+ }
287
+ buildSummary(activity, name) {
288
+ var _a;
289
+ const { id, title, route, screenshots, startTime: startTimeUTC, time: rideTime, distance, startPos, realityFactor = 100, links, laps } = activity;
290
+ const routeId = route === null || route === void 0 ? void 0 : route.id;
291
+ const shots = screenshots !== null && screenshots !== void 0 ? screenshots : [];
292
+ const preview = (_a = shots.find(s => s.isHighlight)) !== null && _a !== void 0 ? _a : shots[0];
293
+ const previewImage = preview === null || preview === void 0 ? void 0 : preview.fileName;
294
+ let startTime;
295
+ if (startTimeUTC)
296
+ startTime = (new Date(startTimeUTC)).getTime();
297
+ const uploadStatus = [];
298
+ if (links === null || links === void 0 ? void 0 : links.strava) {
299
+ uploadStatus.push({ service: 'strava', status: 'success' });
300
+ }
301
+ return {
302
+ id, title, name, routeId, previewImage, startTime, rideTime, distance, startPos, realityFactor, uploadStatus, laps
303
+ };
304
+ }
305
+ scanForActivities() {
306
+ var _a, _b;
307
+ return __awaiter(this, void 0, void 0, function* () {
308
+ try {
309
+ this.isDBComplete = (_a = this.isDBComplete) !== null && _a !== void 0 ? _a : false;
310
+ const names = yield this.listActivities();
311
+ if (!names)
312
+ return null;
313
+ const promises = [];
314
+ names.forEach(name => promises.push(this.loadDetailsByName(name).then((details) => ({ name, details }))));
315
+ const result = yield Promise.allSettled(promises);
316
+ const activities = [];
317
+ let isComplete = true;
318
+ result.forEach(result => {
319
+ var _a;
320
+ if (result.status === "rejected")
321
+ isComplete = false;
322
+ else {
323
+ const details = (_a = result.value) === null || _a === void 0 ? void 0 : _a.details;
324
+ const name = result.value.name;
325
+ const summary = this.buildSummary(details, name);
326
+ activities.push(summary);
327
+ }
328
+ });
329
+ this.isDBComplete = (_b = this.isDBComplete) !== null && _b !== void 0 ? _b : isComplete;
330
+ return activities;
331
+ }
332
+ catch (err) {
333
+ return null;
334
+ }
335
+ });
336
+ }
337
+ scanForActivitiesAndMerge(activities) {
338
+ return __awaiter(this, void 0, void 0, function* () {
339
+ const total = yield this.scanForActivities();
340
+ if (total === null)
341
+ return activities;
342
+ total.forEach(activity => {
343
+ if (!activities.map(a => a.id).includes(activity.id))
344
+ activities.push(activity);
345
+ });
346
+ return activities;
347
+ });
348
+ }
349
+ _load() {
350
+ return __awaiter(this, void 0, void 0, function* () {
351
+ yield this.loadSummaries();
352
+ this.emitDone();
353
+ });
354
+ }
355
+ getActivity(id) {
356
+ return this.activities.find(ai => ai.summary.id === id);
357
+ }
358
+ logError(error, fn, logProps) {
359
+ const props = logProps !== null && logProps !== void 0 ? logProps : {};
360
+ this.logger.logEvent(Object.assign({ message: 'error', error, fn }, props));
361
+ }
362
+ getRepo() {
363
+ if (!this.repo)
364
+ this.repo = api_1.JsonRepository.create('activities');
365
+ return this.repo;
366
+ }
367
+ };
368
+ __setFunctionName(_classThis, "ActivitiesDbLoader");
369
+ (() => {
370
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
371
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
372
+ ActivitiesDbLoader = _classThis = _classDescriptor.value;
373
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
374
+ __runInitializers(_classThis, _classExtraInitializers);
375
+ })();
376
+ return ActivitiesDbLoader = _classThis;
377
+ })();
378
+ exports.ActivitiesDbLoader = ActivitiesDbLoader;
@@ -0,0 +1,2 @@
1
+ export * from './db';
2
+ export * from './types';
@@ -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("./db"), exports);
18
+ __exportStar(require("./types"), exports);
@@ -0,0 +1,8 @@
1
+ import { UploadInfo } from "../model";
2
+ export interface ActivitySearchCriteria {
3
+ routeId?: string;
4
+ startPos?: number;
5
+ realityFactor?: number;
6
+ uploadStatus?: UploadInfo | Array<UploadInfo>;
7
+ isSaved?: boolean;
8
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,116 @@
1
+ import { RoutePoint } from "../../../routes/base/types";
2
+ export type ActivityUser = {
3
+ uuid?: string;
4
+ weight: number;
5
+ ftp: number;
6
+ };
7
+ export type ActivityRoute = {
8
+ id?: string;
9
+ hash: string;
10
+ name: string;
11
+ };
12
+ export type ActivityStatsRecord = {
13
+ min: number;
14
+ max: number;
15
+ avg: number;
16
+ cntVal: number;
17
+ sum: number;
18
+ minAllowed: number;
19
+ };
20
+ export type ActivityLogRecord = {
21
+ time: number;
22
+ timeDelta: number;
23
+ speed: number;
24
+ slope: number;
25
+ cadence: number;
26
+ heartrate: number;
27
+ distance: number;
28
+ power: number;
29
+ lat?: number;
30
+ lon?: number;
31
+ elevation?: number;
32
+ };
33
+ export type ActivityStats = {
34
+ hrm?: ActivityStatsRecord;
35
+ cadence?: ActivityStatsRecord;
36
+ speed: ActivityStatsRecord;
37
+ slope?: ActivityStatsRecord;
38
+ power: ActivityStatsRecord;
39
+ };
40
+ export type StravaAppLink = {
41
+ upload_id: number;
42
+ activity_id: number;
43
+ };
44
+ export type ActivityAppLinks = {
45
+ strava?: StravaAppLink;
46
+ };
47
+ export type ScreenShotInfo = {
48
+ fileName: string;
49
+ position: RoutePoint;
50
+ isHighlight?: boolean;
51
+ };
52
+ export type ActivityType = 'IncyclistActivity';
53
+ export type UploadStatus = 'success' | 'failure';
54
+ export type UploadInfo = {
55
+ service: string;
56
+ status: UploadStatus;
57
+ };
58
+ export type ActivityDB = {
59
+ version: string;
60
+ activities: Array<ActivitySummary>;
61
+ isComplete: boolean;
62
+ };
63
+ export type ActivitySummary = {
64
+ id: string;
65
+ title: string;
66
+ name: string;
67
+ routeId: string;
68
+ previewImage?: string;
69
+ startTime: number;
70
+ rideTime: number;
71
+ distance: number;
72
+ startPos: number;
73
+ realityFactor: number;
74
+ uploadStatus: Array<UploadInfo>;
75
+ isCompleted?: boolean;
76
+ isSaved?: boolean;
77
+ saveRideTime?: number;
78
+ laps?: Array<LapSummary>;
79
+ };
80
+ export type LapSummary = {
81
+ num: number;
82
+ startPos: number;
83
+ distance: number;
84
+ startTime: number;
85
+ rideTime: number;
86
+ };
87
+ export type ActivityDetails = {
88
+ type?: ActivityType;
89
+ version?: string;
90
+ title: string;
91
+ id: string;
92
+ user: ActivityUser;
93
+ route: ActivityRoute;
94
+ startTime: string;
95
+ time: number;
96
+ timeTotal: number;
97
+ timePause: number;
98
+ distance: number;
99
+ startPos: number;
100
+ startpos: number;
101
+ endpos: number;
102
+ totalElevation: number;
103
+ stats: ActivityStats;
104
+ logs: Array<ActivityLogRecord>;
105
+ screenshots: Array<ScreenShotInfo>;
106
+ fileName?: string;
107
+ tcxFileName?: string;
108
+ fitFileName?: string;
109
+ links?: ActivityAppLinks;
110
+ realityFactor: number;
111
+ laps?: Array<LapSummary>;
112
+ };
113
+ export type ActivityInfo = {
114
+ summary: ActivitySummary;
115
+ details?: ActivityDetails;
116
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ export * from './base/model';
2
+ export * from './base/loaders';
@@ -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("./base/model"), exports);
18
+ __exportStar(require("./base/loaders"), exports);
@@ -15,5 +15,6 @@ export declare class JsonRepository {
15
15
  read(objectName: string): Promise<JSONObject>;
16
16
  delete(objectName: string): Promise<boolean>;
17
17
  protected open(): Promise<boolean>;
18
+ list(exclude?: string | Array<string>): Promise<Array<string>>;
18
19
  protected close(): Promise<boolean>;
19
20
  }
@@ -75,6 +75,25 @@ class JsonRepository {
75
75
  }
76
76
  });
77
77
  }
78
+ list(exclude) {
79
+ return __awaiter(this, void 0, void 0, function* () {
80
+ try {
81
+ let names = yield this.access.list();
82
+ if (!names)
83
+ return null;
84
+ names = names.filter(name => name.toLowerCase().endsWith('.json'));
85
+ names = names.map(name => name.substring(0, name.length - 5));
86
+ if (exclude) {
87
+ const excludes = (typeof (exclude) === 'string') ? [exclude] : exclude;
88
+ names = names.filter(name => !excludes.includes(name));
89
+ }
90
+ return names;
91
+ }
92
+ catch (_a) {
93
+ return null;
94
+ }
95
+ });
96
+ }
78
97
  close() {
79
98
  return __awaiter(this, void 0, void 0, function* () {
80
99
  const db = (0, bindings_1.getBindings)().db;
@@ -5,6 +5,7 @@ export type JsonAccess = {
5
5
  read(resourceName: string): Promise<JSONObject>;
6
6
  write(resourceName: string, data: JSONObject): Promise<boolean>;
7
7
  delete(resourceName: string): Promise<boolean>;
8
+ list(): Promise<Array<string>>;
8
9
  };
9
10
  export interface IJsonRepositoryBinding {
10
11
  create(name: string): Promise<JsonAccess | null>;
@@ -27,7 +27,6 @@ export declare class DeviceConfigurationService extends EventEmitter {
27
27
  protected logError(err: Error, fn: string): void;
28
28
  init(): Promise<void>;
29
29
  setFeature(name: string, enabled: boolean): void;
30
- protected isNewUi(): boolean;
31
30
  protected verifyCapabilityExists(capability: any): void;
32
31
  protected verifyCapabilitySettings(): void;
33
32
  protected initCapabilties(): void;
@@ -106,9 +106,6 @@ class DeviceConfigurationService extends events_1.default {
106
106
  setFeature(name, enabled) {
107
107
  this.features[name] = enabled;
108
108
  }
109
- isNewUi() {
110
- return this.features['NEW_UI'] === true;
111
- }
112
109
  verifyCapabilityExists(capability) {
113
110
  const { capabilities } = this.settings;
114
111
  const found = capabilities.find(c => c.capability === capability);
@@ -117,74 +114,20 @@ class DeviceConfigurationService extends events_1.default {
117
114
  }
118
115
  }
119
116
  verifyCapabilitySettings() {
120
- var _a;
121
117
  const { capabilities } = this.settings;
122
- const isNewUi = this.isNewUi();
123
118
  const bikeCapIdx = capabilities.findIndex(c => c.capability === 'bike');
124
- if (isNewUi) {
125
- this.verifyCapabilityExists(incyclist_devices_1.IncyclistCapability.Control);
126
- this.verifyCapabilityExists(incyclist_devices_1.IncyclistCapability.Power);
127
- this.verifyCapabilityExists(incyclist_devices_1.IncyclistCapability.HeartRate);
128
- this.verifyCapabilityExists(incyclist_devices_1.IncyclistCapability.Speed);
129
- this.verifyCapabilityExists(incyclist_devices_1.IncyclistCapability.Cadence);
130
- if (bikeCapIdx !== -1) {
131
- capabilities.splice(bikeCapIdx, 1);
132
- }
133
- return;
134
- }
135
- else {
136
- if (bikeCapIdx === -1) {
137
- const control = capabilities.find(c => c.capability === incyclist_devices_1.IncyclistCapability.Control && c.selected !== undefined);
138
- const bike = Object.assign({}, control);
139
- bike.capability = 'bike';
140
- capabilities.push(bike);
141
- }
142
- }
143
- const bikeCap = capabilities.find(c => c.capability === 'bike');
144
- for (const capability of ['bike', incyclist_devices_1.IncyclistCapability.Control]) {
145
- const info = capabilities.find(c => c.capability === capability);
146
- if (((_a = info === null || info === void 0 ? void 0 : info.devices) === null || _a === void 0 ? void 0 : _a.length) > 0 && (info === null || info === void 0 ? void 0 : info.selected) === undefined)
147
- this.select(info.devices[0], capability);
148
- }
149
- if (bikeCap === null || bikeCap === void 0 ? void 0 : bikeCap.selected) {
150
- const bike = bikeCap.selected;
151
- const power = capabilities.find(c => c.capability === incyclist_devices_1.IncyclistCapability.Power && c.selected !== undefined);
152
- const control = capabilities.find(c => c.capability === incyclist_devices_1.IncyclistCapability.Control && c.selected !== undefined);
153
- const speed = capabilities.find(c => c.capability === incyclist_devices_1.IncyclistCapability.Speed && c.selected !== undefined);
154
- const cadence = capabilities.find(c => c.capability === incyclist_devices_1.IncyclistCapability.Cadence && c.selected !== undefined);
155
- const adapter = this.getAdapter(bike);
156
- let changed = false;
157
- const verify = (uuid, cap) => {
158
- if (!uuid && adapter.hasCapability(cap)) {
159
- const setting = capabilities.find(c => c.capability === cap);
160
- if (!setting) {
161
- capabilities.push({ capability: cap, devices: [bike], selected: bike, disabled: false });
162
- changed = true;
163
- }
164
- else {
165
- setting.selected = bike;
166
- if (!setting.devices.includes(bike))
167
- setting.devices.push(bike);
168
- changed = true;
169
- }
170
- }
171
- };
172
- verify(control, incyclist_devices_1.IncyclistCapability.Control);
173
- verify(power, incyclist_devices_1.IncyclistCapability.Power);
174
- verify(speed, incyclist_devices_1.IncyclistCapability.Speed);
175
- verify(cadence, incyclist_devices_1.IncyclistCapability.Cadence);
176
- if (changed) {
177
- this.updateUserSettings();
178
- this.logEvent({ message: 'capability changed after verification', capabilities });
179
- }
119
+ this.verifyCapabilityExists(incyclist_devices_1.IncyclistCapability.Control);
120
+ this.verifyCapabilityExists(incyclist_devices_1.IncyclistCapability.Power);
121
+ this.verifyCapabilityExists(incyclist_devices_1.IncyclistCapability.HeartRate);
122
+ this.verifyCapabilityExists(incyclist_devices_1.IncyclistCapability.Speed);
123
+ this.verifyCapabilityExists(incyclist_devices_1.IncyclistCapability.Cadence);
124
+ if (bikeCapIdx !== -1) {
125
+ capabilities.splice(bikeCapIdx, 1);
180
126
  }
127
+ return;
181
128
  }
182
129
  initCapabilties() {
183
- const isNewUi = this.isNewUi();
184
130
  const target = [incyclist_devices_1.IncyclistCapability.Control, incyclist_devices_1.IncyclistCapability.Power, incyclist_devices_1.IncyclistCapability.Cadence, incyclist_devices_1.IncyclistCapability.Speed, incyclist_devices_1.IncyclistCapability.HeartRate];
185
- if (!isNewUi) {
186
- target.push('bike');
187
- }
188
131
  if (!this.settings)
189
132
  this.settings = {};
190
133
  if (!this.settings.capabilities)
@@ -213,11 +156,7 @@ class DeviceConfigurationService extends events_1.default {
213
156
  var _a, _b, _c, _d, _e;
214
157
  const { gearSelection, connections, modeSettings = {} } = settings;
215
158
  this.logEvent({ message: 'converting settings.json', gearSelection, connections });
216
- const isNewUi = this.isNewUi();
217
159
  const all = [incyclist_devices_1.IncyclistCapability.Control, incyclist_devices_1.IncyclistCapability.Power, incyclist_devices_1.IncyclistCapability.Cadence, incyclist_devices_1.IncyclistCapability.Speed, incyclist_devices_1.IncyclistCapability.HeartRate];
218
- if (!isNewUi) {
219
- all.push('bike');
220
- }
221
160
  const gears = (0, clone_1.default)(gearSelection || {});
222
161
  const { bikes = [], hrms = [] } = gears;
223
162
  this.settings = { interfaces: [], devices: [], capabilities: [] };
@@ -275,7 +214,7 @@ class DeviceConfigurationService extends events_1.default {
275
214
  this.addToCapability(udid, cc);
276
215
  if (isSelected) {
277
216
  const cap = cc;
278
- if ((!isNewUi && cap === 'bike') || adapter.hasCapability(cap)) {
217
+ if (adapter.hasCapability(cap)) {
279
218
  const selectedDevice = capabilities.find(c => c.capability === cap);
280
219
  selectedDevice.selected = udid;
281
220
  }
@@ -407,8 +346,7 @@ class DeviceConfigurationService extends events_1.default {
407
346
  select(udid, capability, props) {
408
347
  var _a, _b, _c;
409
348
  this.logEvent({ message: 'select device', udid, capability, props });
410
- const isNewUi = this.isNewUi();
411
- const { noRecursive = false, legacy = false, emit = true } = props || {};
349
+ const { emit = true } = props || {};
412
350
  const deviceSettings = (_b = (_a = this.settings.devices) === null || _a === void 0 ? void 0 : _a.find(d => d.udid === udid)) === null || _b === void 0 ? void 0 : _b.settings;
413
351
  if (!deviceSettings)
414
352
  return;
@@ -417,62 +355,13 @@ class DeviceConfigurationService extends events_1.default {
417
355
  this.logEvent({ message: 'error: could not find adapter', fn: 'select', udid, capability, adapters: (_c = Object.keys(this.adapters)) === null || _c === void 0 ? void 0 : _c.join(',') });
418
356
  return;
419
357
  }
420
- if (isNewUi) {
421
- if (capability === 'bike')
422
- return;
423
- this.selectSingleDevice(udid, capability);
424
- if (emit)
425
- this.emitCapabiltyChanged(capability);
426
- this.updateUserSettings();
427
- return;
428
- }
429
- if ((capability === 'bike') && !adapter.isControllable())
358
+ if (capability === 'bike')
430
359
  return;
431
- const isControl = adapter.hasCapability(incyclist_devices_1.IncyclistCapability.Control) || (legacy && !isNewUi && capability === 'bike');
432
360
  this.selectSingleDevice(udid, capability);
433
- this.emitCapabiltyChanged(capability);
434
- if (noRecursive)
435
- return;
436
- if (isControl) {
437
- if (capability !== 'bike' && capability !== incyclist_devices_1.IncyclistCapability.Control) {
438
- if (!isNewUi)
439
- this.select(udid, 'bike', { noRecursive: true, legacy });
440
- this.select(udid, incyclist_devices_1.IncyclistCapability.Control, { noRecursive: true, legacy });
441
- }
442
- else {
443
- if (!isNewUi && capability === 'bike' && isControl) {
444
- this.select(udid, incyclist_devices_1.IncyclistCapability.Control, { noRecursive: true, legacy });
445
- this.select(udid, incyclist_devices_1.IncyclistCapability.Power, { noRecursive: true, legacy });
446
- if (legacy) {
447
- this.select(udid, incyclist_devices_1.IncyclistCapability.Speed, { noRecursive: true, legacy });
448
- this.select(udid, incyclist_devices_1.IncyclistCapability.Cadence, { noRecursive: true, legacy });
449
- }
450
- if (adapter.hasCapability(incyclist_devices_1.IncyclistCapability.HeartRate)) {
451
- const hrm = this.getSelected(incyclist_devices_1.IncyclistCapability.HeartRate);
452
- if (!hrm && !this.isDisabled(incyclist_devices_1.IncyclistCapability.HeartRate)) {
453
- this.select(udid, incyclist_devices_1.IncyclistCapability.HeartRate);
454
- }
455
- else if (hrm && hrm.hasCapability(incyclist_devices_1.IncyclistCapability.Control)) {
456
- this.select(udid, incyclist_devices_1.IncyclistCapability.HeartRate);
457
- }
458
- }
459
- }
460
- const otherCapabilties = this.settings.capabilities.filter(c => c.capability !== 'bike' && c.capability !== incyclist_devices_1.IncyclistCapability.Control && !c.disabled && c.selected !== udid);
461
- const selectedControllable = otherCapabilties.filter(c => { var _a; return c.selected && ((_a = this.adapters[c.selected]) === null || _a === void 0 ? void 0 : _a.hasCapability(incyclist_devices_1.IncyclistCapability.Control)); });
462
- selectedControllable.forEach(c => {
463
- if (adapter.hasCapability(c.capability)) {
464
- this.select(udid, c.capability);
465
- }
466
- else
467
- this.unselect(c.capability);
468
- });
469
- }
470
- }
471
- else if (!isControl && !isNewUi && capability === 'bike') {
472
- this.unselect(incyclist_devices_1.IncyclistCapability.Control);
473
- this.select(udid, incyclist_devices_1.IncyclistCapability.Power, { noRecursive: true, legacy });
474
- }
361
+ if (emit)
362
+ this.emitCapabiltyChanged(capability);
475
363
  this.updateUserSettings();
364
+ return;
476
365
  }
477
366
  selectSingleDevice(udid, capability) {
478
367
  var _a;
@@ -496,7 +385,6 @@ class DeviceConfigurationService extends events_1.default {
496
385
  }
497
386
  add(deviceSettings, props) {
498
387
  var _a, _b;
499
- const isNewUi = this.isNewUi();
500
388
  let udid = this.getUdid(deviceSettings);
501
389
  const { legacy = false } = props || {};
502
390
  this.logEvent({ message: 'add device', udid, deviceSettings, legacy });
@@ -525,30 +413,10 @@ class DeviceConfigurationService extends events_1.default {
525
413
  if (c.devices.includes(udid))
526
414
  return udid;
527
415
  const isBike = adapter.hasCapability(incyclist_devices_1.IncyclistCapability.Control);
528
- const isPower = adapter.hasCapability(incyclist_devices_1.IncyclistCapability.Power);
529
- if (legacy && !isNewUi) {
530
- const isBikeCap = c.capability === 'bike';
531
- const isControlCap = c.capability === incyclist_devices_1.IncyclistCapability.Control;
532
- const isHrmCap = c.capability === incyclist_devices_1.IncyclistCapability.HeartRate;
533
- const canAdd = (isBikeCap && (isBike || isPower)) ||
534
- (isControlCap && isBike) ||
535
- (!isHrmCap && !isControlCap && (isBike || isPower)) ||
536
- adapter.hasCapability(c.capability);
537
- const canSelect = (isBikeCap || isControlCap || isHrmCap) &&
538
- (!c.selected && !c.disabled &&
539
- (isBike || isPower || c.capability === incyclist_devices_1.IncyclistCapability.HeartRate));
540
- if (canAdd) {
541
- c.devices.push(udid);
542
- if (canSelect)
543
- c.selected = udid;
544
- }
545
- }
546
- else {
547
- if (adapter.hasCapability(c.capability) || (!isNewUi && c.capability === 'bike' && (isBike || isPower))) {
548
- c.devices.push(udid);
549
- if (!c.selected && !c.disabled && (isBike || c.capability === incyclist_devices_1.IncyclistCapability.HeartRate))
550
- c.selected = udid;
551
- }
416
+ if (adapter.hasCapability(c.capability) && c.capability !== 'bike') {
417
+ c.devices.push(udid);
418
+ if (!c.selected && !c.disabled && (isBike || c.capability === incyclist_devices_1.IncyclistCapability.HeartRate))
419
+ c.selected = udid;
552
420
  }
553
421
  });
554
422
  this.updateUserSettings();
@@ -611,8 +479,8 @@ class DeviceConfigurationService extends events_1.default {
611
479
  }
612
480
  }
613
481
  addToCapability(udid, capability) {
614
- const isNewUi = this.isNewUi();
615
- if (isNewUi && capability === 'bike')
482
+ var _a;
483
+ if (capability === 'bike')
616
484
  return;
617
485
  if (!this.settings)
618
486
  this.settings = {};
@@ -624,12 +492,9 @@ class DeviceConfigurationService extends events_1.default {
624
492
  capabilities.push({ capability, devices: [udid], selected: udid });
625
493
  }
626
494
  else {
627
- if (!record.devices.includes(udid))
495
+ if (!((_a = record.devices) === null || _a === void 0 ? void 0 : _a.includes(udid)))
628
496
  record.devices.push(udid);
629
497
  }
630
- if (capability !== 'bike' && !this.adapters[udid].hasCapability(capability)) {
631
- this.adapters[udid].addCapability(capability);
632
- }
633
498
  }
634
499
  getUdid(deviceSettings) {
635
500
  const udids = Object.keys(this.adapters);
@@ -661,12 +526,10 @@ class DeviceConfigurationService extends events_1.default {
661
526
  this.userSettings.set('interfaces', this.settings.interfaces);
662
527
  }
663
528
  canStartRide() {
664
- const isNewUi = this.isNewUi();
665
529
  const { devices, capabilities } = this.settings || {};
666
530
  if (!devices || !capabilities)
667
531
  return false;
668
- const canStart = ((!isNewUi && this.getSelected('bike') !== undefined) ||
669
- this.getSelected(incyclist_devices_1.IncyclistCapability.Control) !== undefined ||
532
+ const canStart = (this.getSelected(incyclist_devices_1.IncyclistCapability.Control) !== undefined ||
670
533
  this.getSelected(incyclist_devices_1.IncyclistCapability.Power) !== undefined ||
671
534
  this.getSelected(incyclist_devices_1.IncyclistCapability.Speed) !== undefined);
672
535
  return canStart;
package/lib/index.d.ts CHANGED
@@ -4,4 +4,5 @@ export * from './api';
4
4
  export * from './routes';
5
5
  export * from './workouts';
6
6
  export * from './coaches';
7
+ export * from './activities';
7
8
  export { useUserSettings, initUserSettings, UserSettingsService, UserSettingsBinding, IUserSettingsBinding } from './settings';
package/lib/index.js CHANGED
@@ -21,6 +21,7 @@ __exportStar(require("./api"), exports);
21
21
  __exportStar(require("./routes"), exports);
22
22
  __exportStar(require("./workouts"), exports);
23
23
  __exportStar(require("./coaches"), exports);
24
+ __exportStar(require("./activities"), exports);
24
25
  var settings_1 = require("./settings");
25
26
  Object.defineProperty(exports, "useUserSettings", { enumerable: true, get: function () { return settings_1.useUserSettings; } });
26
27
  Object.defineProperty(exports, "initUserSettings", { enumerable: true, get: function () { return settings_1.initUserSettings; } });
@@ -7,7 +7,7 @@ exports.getPosition = exports.getNextPosition = exports.getRouteHash = exports.g
7
7
  const utils_1 = require("../../../utils");
8
8
  const geo_1 = require("../../../utils/geo");
9
9
  const valid_1 = require("../../../utils/valid");
10
- const md5_1 = __importDefault(require("md5"));
10
+ const crypto_1 = __importDefault(require("crypto"));
11
11
  const MAX_LAPMODE_DISTANCE = 50;
12
12
  const checkIsLoop = (_route) => {
13
13
  var _a;
@@ -155,7 +155,7 @@ const getRouteHash = (route) => {
155
155
  else {
156
156
  json = { decoded: route.points.map(p => ({ lat: p.lat, lng: p.lng })) };
157
157
  }
158
- const routeHash = (0, md5_1.default)(JSON.stringify(json));
158
+ const routeHash = crypto_1.default.createHash('md5').update(JSON.stringify(json)).digest('hex');
159
159
  return routeHash;
160
160
  };
161
161
  exports.getRouteHash = getRouteHash;
@@ -7,7 +7,7 @@ exports.Plan = exports.Workout = void 0;
7
7
  const Step_1 = require("./Step");
8
8
  const Segment_1 = require("./Segment");
9
9
  const valid_1 = require("../../../utils/valid");
10
- const md5_1 = __importDefault(require("md5"));
10
+ const crypto_1 = __importDefault(require("crypto"));
11
11
  class Workout extends Segment_1.Segment {
12
12
  constructor(opts) {
13
13
  var _a;
@@ -36,7 +36,7 @@ class Workout extends Segment_1.Segment {
36
36
  if (this._hash)
37
37
  return this.hash;
38
38
  const { name, description, steps, repeat } = this;
39
- this._hash = (0, md5_1.default)(JSON.stringify({ name, description, steps, repeat }));
39
+ this._hash = crypto_1.default.createHash('md5').update(JSON.stringify({ name, description, steps, repeat })).digest('hex');
40
40
  return this._hash;
41
41
  }
42
42
  getSegment(time) {
@@ -85,7 +85,8 @@ class Plan {
85
85
  if (this._hash)
86
86
  return this.hash;
87
87
  const { name, description, workouts } = this;
88
- this._hash = (0, md5_1.default)(JSON.stringify({ name, description, workouts }));
88
+ const data = JSON.stringify({ name, description, workouts });
89
+ this._hash = crypto_1.default.createHash('md5').update(data).digest('hex');
89
90
  return this._hash;
90
91
  }
91
92
  addWorkoutSchedule(week, day, workoutId) {
@@ -19,7 +19,7 @@ export declare class WorkoutCard extends BaseCard implements Card<Workout> {
19
19
  select(settings?: WorkoutSettings): void;
20
20
  unselect(): void;
21
21
  move(targetListName: string): void;
22
- save(): Promise<void>;
22
+ save(enforce?: boolean): Promise<void>;
23
23
  delete(): PromiseObserver<boolean>;
24
24
  getId(): string;
25
25
  getTitle(): string;
@@ -71,12 +71,12 @@ class WorkoutCard extends base_1.BaseCard {
71
71
  this.list = newList;
72
72
  }
73
73
  this.workout.category = { name: targetListName, index: newList === null || newList === void 0 ? void 0 : newList.length };
74
- this.save();
74
+ this.save(true);
75
75
  }
76
- save() {
76
+ save(enforce = false) {
77
77
  return __awaiter(this, void 0, void 0, function* () {
78
78
  try {
79
- return yield this.getRepo().save(this.workout);
79
+ return yield this.getRepo().save(this.workout, enforce);
80
80
  }
81
81
  catch (err) {
82
82
  this.logError(err, 'save');
@@ -16,7 +16,7 @@ export declare class WorkoutsDbLoader extends Loader {
16
16
  constructor();
17
17
  load(): Observer;
18
18
  stopLoad(): void;
19
- save(workout: Workout | Plan): Promise<void>;
19
+ save(workout: Workout | Plan, enforceWrite?: boolean): Promise<void>;
20
20
  delete(workout: Workout | Plan): Promise<void>;
21
21
  protected getRepo(): JsonRepository;
22
22
  protected _load(): Promise<void>;
@@ -85,7 +85,7 @@ let WorkoutsDbLoader = (() => {
85
85
  });
86
86
  }
87
87
  }
88
- save(workout) {
88
+ save(workout, enforceWrite = false) {
89
89
  return __awaiter(this, void 0, void 0, function* () {
90
90
  if (!(0, valid_1.valid)(workout))
91
91
  return;
@@ -106,9 +106,9 @@ let WorkoutsDbLoader = (() => {
106
106
  else {
107
107
  prev = stringify(Object.assign({}, this.workouts[idx]));
108
108
  this.workouts[idx] = workout;
109
- changed = stringify(Object.assign({}, this.workouts[idx])) !== prev;
109
+ changed = stringify(Object.assign({}, workout)) !== prev;
110
110
  }
111
- if (changed) {
111
+ if (changed || enforceWrite) {
112
112
  this.isDirty = true;
113
113
  this.write();
114
114
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "incyclist-services",
3
- "version": "1.1.102",
3
+ "version": "1.2.1",
4
4
  "peerDependencies": {
5
5
  "gd-eventlog": "^0.1.26"
6
6
  },
@@ -39,8 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "axios": "^1.6.1",
42
- "incyclist-devices": "^2.1.41",
43
- "md5": "^2.3.0",
42
+ "incyclist-devices": "^2.2.1",
44
43
  "promise.any": "^2.0.6",
45
44
  "uuid": "^9.0.0",
46
45
  "xml2js": "^0.6.2"