signalk-maintenance-tracker 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/LICENSE +201 -0
  3. package/README.md +75 -0
  4. package/dist/api/router.js +193 -0
  5. package/dist/api/router.js.map +1 -0
  6. package/dist/auth.js +22 -0
  7. package/dist/auth.js.map +1 -0
  8. package/dist/config.js +50 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/db/database.js +47 -0
  11. package/dist/db/database.js.map +1 -0
  12. package/dist/db/logs.repo.js +91 -0
  13. package/dist/db/logs.repo.js.map +1 -0
  14. package/dist/db/migrations.js +57 -0
  15. package/dist/db/migrations.js.map +1 -0
  16. package/dist/db/tags.repo.js +78 -0
  17. package/dist/db/tags.repo.js.map +1 -0
  18. package/dist/db/tasks.repo.js +78 -0
  19. package/dist/db/tasks.repo.js.map +1 -0
  20. package/dist/domain/slug.js +27 -0
  21. package/dist/domain/slug.js.map +1 -0
  22. package/dist/domain/status.js +110 -0
  23. package/dist/domain/status.js.map +1 -0
  24. package/dist/index.js +130 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/service.js +370 -0
  27. package/dist/service.js.map +1 -0
  28. package/dist/signalk/notifications.js +115 -0
  29. package/dist/signalk/notifications.js.map +1 -0
  30. package/dist/signalk/runtime.js +103 -0
  31. package/dist/signalk/runtime.js.map +1 -0
  32. package/dist/types.js +11 -0
  33. package/dist/types.js.map +1 -0
  34. package/docs/screenshots/completed.png +0 -0
  35. package/docs/screenshots/dark-mode.png +0 -0
  36. package/docs/screenshots/edit-task.png +0 -0
  37. package/docs/screenshots/homepage.png +0 -0
  38. package/docs/screenshots/main-log.png +0 -0
  39. package/docs/screenshots/task-detail.png +0 -0
  40. package/package.json +82 -0
  41. package/public/app/api/client.js +75 -0
  42. package/public/app/api/hooks.js +159 -0
  43. package/public/app/api/resource.js +156 -0
  44. package/public/app/api/signalkPaths.js +66 -0
  45. package/public/app/app.js +71 -0
  46. package/public/app/auth/auth.js +158 -0
  47. package/public/app/components/AuthControl.js +22 -0
  48. package/public/app/components/ConfirmModal.js +55 -0
  49. package/public/app/components/LogEntryModal.js +150 -0
  50. package/public/app/components/LoginModal.js +86 -0
  51. package/public/app/components/MarkdownView.js +17 -0
  52. package/public/app/components/Modal.js +89 -0
  53. package/public/app/components/Pagination.js +35 -0
  54. package/public/app/components/PathPicker.js +66 -0
  55. package/public/app/components/ProgressBar.js +26 -0
  56. package/public/app/components/StatusBadge.js +9 -0
  57. package/public/app/components/Table.js +99 -0
  58. package/public/app/components/TagInput.js +93 -0
  59. package/public/app/components/TaskFormModal.js +310 -0
  60. package/public/app/components/ThemeToggle.js +17 -0
  61. package/public/app/components/Toaster.js +24 -0
  62. package/public/app/lib/format.js +90 -0
  63. package/public/app/lib/html.js +6 -0
  64. package/public/app/lib/router.js +105 -0
  65. package/public/app/lib/sanitize.js +64 -0
  66. package/public/app/lib/slug.js +16 -0
  67. package/public/app/lib/theme.js +52 -0
  68. package/public/app/lib/toasts.js +33 -0
  69. package/public/app/lib/useListParams.js +28 -0
  70. package/public/app/main.js +20 -0
  71. package/public/app/pages/MasterLogPage.js +279 -0
  72. package/public/app/pages/TaskDetailPage.js +294 -0
  73. package/public/app/pages/TaskListPage.js +279 -0
  74. package/public/app/types.js +90 -0
  75. package/public/icons/apple-touch-icon.png +0 -0
  76. package/public/icons/favicon-16.png +0 -0
  77. package/public/icons/favicon-32.png +0 -0
  78. package/public/icons/favicon.ico +0 -0
  79. package/public/icons/icon-192.png +0 -0
  80. package/public/icons/icon-512.png +0 -0
  81. package/public/index.html +82 -0
  82. package/public/manifest.webmanifest +37 -0
  83. package/public/styles/main.css +787 -0
  84. package/public/styles/tokens.css +55 -0
  85. package/public/vendor/VERSIONS.json +9 -0
  86. package/public/vendor/bootstrap-icons/bootstrap-icons.css +2106 -0
  87. package/public/vendor/bootstrap-icons/fonts/bootstrap-icons.woff +0 -0
  88. package/public/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 +0 -0
  89. package/public/vendor/dayjs/constant.js +25 -0
  90. package/public/vendor/dayjs/index.d.ts +1 -0
  91. package/public/vendor/dayjs/index.js +541 -0
  92. package/public/vendor/dayjs/locale/en.js +12 -0
  93. package/public/vendor/dayjs/utils.js +58 -0
  94. package/public/vendor/htm.d.ts +1 -0
  95. package/public/vendor/htm.js +1 -0
  96. package/public/vendor/preact-hooks.d.ts +1 -0
  97. package/public/vendor/preact-hooks.js +2 -0
  98. package/public/vendor/preact.d.ts +1 -0
  99. package/public/vendor/preact.js +2 -0
  100. package/public/vendor/signals-core.d.ts +1 -0
  101. package/public/vendor/signals-core.js +1 -0
  102. package/public/vendor/signals.d.ts +1 -0
  103. package/public/vendor/signals.js +1 -0
  104. package/public/vendor/snarkdown.d.ts +1 -0
  105. package/public/vendor/snarkdown.js +2 -0
@@ -0,0 +1,370 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MaintenanceService = exports.ApiError = void 0;
4
+ const logs_repo_1 = require("./db/logs.repo");
5
+ const tags_repo_1 = require("./db/tags.repo");
6
+ const tasks_repo_1 = require("./db/tasks.repo");
7
+ const slug_1 = require("./domain/slug");
8
+ const status_1 = require("./domain/status");
9
+ const types_1 = require("./types");
10
+ class ApiError extends Error {
11
+ status;
12
+ code;
13
+ constructor(status, code, message) {
14
+ super(message);
15
+ this.status = status;
16
+ this.code = code;
17
+ }
18
+ }
19
+ exports.ApiError = ApiError;
20
+ const DEFAULT_PAGE_SIZE = 20;
21
+ const MAX_PAGE_SIZE = 200;
22
+ class MaintenanceService {
23
+ db;
24
+ deps;
25
+ tasks;
26
+ logs;
27
+ tags;
28
+ constructor(db, deps) {
29
+ this.db = db;
30
+ this.deps = deps;
31
+ this.tasks = new tasks_repo_1.TasksRepo(db);
32
+ this.logs = new logs_repo_1.LogsRepo(db);
33
+ this.tags = new tags_repo_1.TagsRepo(db);
34
+ }
35
+ now() {
36
+ return this.deps.now ? this.deps.now() : new Date();
37
+ }
38
+ emit(event = {}) {
39
+ this.deps.onMutation?.(event);
40
+ }
41
+ // ---- DTO assembly ----
42
+ toDTO(row, tags) {
43
+ const current = row.runtime_path
44
+ ? this.deps.getRuntime(row.runtime_path)
45
+ : null;
46
+ const computed = (0, status_1.computeTask)(row, current, this.now(), this.deps.config);
47
+ return {
48
+ id: row.id,
49
+ slug: row.slug,
50
+ name: row.name,
51
+ description: row.description,
52
+ tags,
53
+ runtime_interval: row.runtime_interval,
54
+ time_interval: row.time_interval,
55
+ time_interval_unit: row.time_interval_unit,
56
+ runtime_path: row.runtime_path,
57
+ last_maintenance: row.last_maintenance,
58
+ last_runtime: row.last_runtime,
59
+ created_at: row.created_at,
60
+ updated_at: row.updated_at,
61
+ ...computed,
62
+ };
63
+ }
64
+ // ---- tasks ----
65
+ listTasks(q) {
66
+ const page = Math.max(1, q.page ?? 1);
67
+ const pageSize = Math.min(MAX_PAGE_SIZE, Math.max(1, q.pageSize ?? DEFAULT_PAGE_SIZE));
68
+ const tagsByTask = this.tags.tagsByTask();
69
+ let items = this.tasks
70
+ .listAll()
71
+ .map((row) => this.toDTO(row, tagsByTask.get(row.id) ?? []));
72
+ if (q.search) {
73
+ const needle = q.search.toLowerCase();
74
+ const noteMatches = this.logs.taskIdsWithNotesLike(`%${q.search}%`);
75
+ items = items.filter((t) => t.name.toLowerCase().includes(needle) ||
76
+ (t.description ?? '').toLowerCase().includes(needle) ||
77
+ t.tags.some((tag) => tag.toLowerCase().includes(needle)) ||
78
+ noteMatches.has(t.id));
79
+ }
80
+ if (q.tags && q.tags.length) {
81
+ const wanted = q.tags.map((t) => t.toLowerCase());
82
+ items = items.filter((t) => {
83
+ const have = t.tags.map((x) => x.toLowerCase());
84
+ return wanted.every((w) => have.includes(w));
85
+ });
86
+ }
87
+ if (q.status && q.status.length) {
88
+ const set = new Set(q.status);
89
+ items = items.filter((t) => set.has(t.status));
90
+ }
91
+ const dir = q.order === 'desc' ? -1 : 1;
92
+ const byName = (a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: 'base' });
93
+ // nulls always sort last regardless of direction
94
+ const byNullable = (a, b) => {
95
+ if (a == null && b == null)
96
+ return 0;
97
+ if (a == null)
98
+ return 1;
99
+ if (b == null)
100
+ return -1;
101
+ return dir * (a - b);
102
+ };
103
+ switch (q.sort) {
104
+ case 'name':
105
+ items.sort((a, b) => dir * byName(a, b));
106
+ break;
107
+ case 'remaining_runtime':
108
+ items.sort((a, b) => byNullable(a.remaining_runtime, b.remaining_runtime) ||
109
+ byName(a, b));
110
+ break;
111
+ case 'remaining_time':
112
+ items.sort((a, b) => byNullable(a.remaining_time_ms, b.remaining_time_ms) ||
113
+ byName(a, b));
114
+ break;
115
+ case 'status':
116
+ default:
117
+ // default sort: most urgent first — status rank, then highest fraction
118
+ items.sort((a, b) => dir * (a.status_rank - b.status_rank || b.urgency - a.urgency) ||
119
+ byName(a, b));
120
+ break;
121
+ }
122
+ const total = items.length;
123
+ const data = items.slice((page - 1) * pageSize, page * pageSize);
124
+ return { data, total, page, pageSize };
125
+ }
126
+ listAllComputed() {
127
+ const tagsByTask = this.tags.tagsByTask();
128
+ return this.tasks
129
+ .listAll()
130
+ .map((row) => this.toDTO(row, tagsByTask.get(row.id) ?? []));
131
+ }
132
+ getTask(slug) {
133
+ const row = this.requireTask(slug);
134
+ return this.toDTO(row, this.tags.tagsForTask(row.id));
135
+ }
136
+ createTask(body) {
137
+ const name = (body.name ?? '').trim();
138
+ if (!name)
139
+ throw new ApiError(400, 'invalid_name', 'Task name is required');
140
+ this.validateIntervals(body.runtime_interval, body.time_interval, body.time_interval_unit);
141
+ let slug;
142
+ if (body.slug != null && body.slug.trim() !== '') {
143
+ slug = (0, slug_1.slugify)(body.slug);
144
+ if (this.tasks.slugExists(slug))
145
+ throw new ApiError(409, 'slug_conflict', `Slug "${slug}" is already in use`);
146
+ }
147
+ else {
148
+ slug = (0, slug_1.uniqueSlug)((0, slug_1.slugify)(name), (s) => this.tasks.slugExists(s));
149
+ }
150
+ const nowIso = this.now().toISOString();
151
+ const seed = {
152
+ slug,
153
+ name,
154
+ description: body.description ?? null,
155
+ runtime_interval: body.runtime_interval ?? null,
156
+ time_interval: body.time_interval ?? null,
157
+ time_interval_unit: body.time_interval_unit ?? null,
158
+ runtime_path: body.runtime_path?.trim() || null,
159
+ last_maintenance: body.last_maintenance ?? null,
160
+ last_runtime: body.last_runtime ?? null,
161
+ seed_last_maintenance: body.last_maintenance ?? null,
162
+ seed_last_runtime: body.last_runtime ?? null,
163
+ };
164
+ const row = this.tasks.create(seed, nowIso);
165
+ if (body.tags)
166
+ this.tags.setTaskTags(row.id, body.tags);
167
+ this.emit();
168
+ return this.toDTO(this.tasks.getById(row.id), this.tags.tagsForTask(row.id));
169
+ }
170
+ updateTask(slug, body) {
171
+ const row = this.requireTask(slug);
172
+ const merged = {
173
+ slug: row.slug,
174
+ name: body.name !== undefined ? (body.name ?? '').trim() : row.name,
175
+ description: body.description !== undefined ? body.description : row.description,
176
+ runtime_interval: body.runtime_interval !== undefined
177
+ ? body.runtime_interval
178
+ : row.runtime_interval,
179
+ time_interval: body.time_interval !== undefined
180
+ ? body.time_interval
181
+ : row.time_interval,
182
+ time_interval_unit: body.time_interval_unit !== undefined
183
+ ? body.time_interval_unit
184
+ : row.time_interval_unit,
185
+ runtime_path: body.runtime_path !== undefined
186
+ ? body.runtime_path?.trim() || null
187
+ : row.runtime_path,
188
+ last_maintenance: row.last_maintenance,
189
+ last_runtime: row.last_runtime,
190
+ seed_last_maintenance: row.seed_last_maintenance,
191
+ seed_last_runtime: row.seed_last_runtime,
192
+ };
193
+ if (!merged.name)
194
+ throw new ApiError(400, 'invalid_name', 'Task name is required');
195
+ this.validateIntervals(merged.runtime_interval, merged.time_interval, merged.time_interval_unit);
196
+ // Slug change: normalize, uniqueness-check, remember old slug so the
197
+ // notification path can be migrated (§6.4).
198
+ let clearedSlug;
199
+ if (body.slug !== undefined &&
200
+ body.slug != null &&
201
+ body.slug.trim() !== '') {
202
+ const newSlug = (0, slug_1.slugify)(body.slug);
203
+ if (newSlug !== row.slug) {
204
+ if (this.tasks.slugExists(newSlug, row.id))
205
+ throw new ApiError(409, 'slug_conflict', `Slug "${newSlug}" is already in use`);
206
+ merged.slug = newSlug;
207
+ clearedSlug = row.slug;
208
+ }
209
+ }
210
+ // Seed last_* may only be edited while the task has no log entries (§8.1)
211
+ const hasLogs = this.logs.countForTask(row.id) > 0;
212
+ if (!hasLogs) {
213
+ if (body.last_maintenance !== undefined) {
214
+ merged.seed_last_maintenance = body.last_maintenance;
215
+ merged.last_maintenance = body.last_maintenance;
216
+ }
217
+ if (body.last_runtime !== undefined) {
218
+ merged.seed_last_runtime = body.last_runtime;
219
+ merged.last_runtime = body.last_runtime;
220
+ }
221
+ }
222
+ this.tasks.update(row.id, merged, this.now().toISOString());
223
+ if (body.tags !== undefined)
224
+ this.tags.setTaskTags(row.id, body.tags ?? []);
225
+ this.emit({ clearedSlug });
226
+ return this.toDTO(this.tasks.getById(row.id), this.tags.tagsForTask(row.id));
227
+ }
228
+ deleteTask(slug) {
229
+ const row = this.requireTask(slug);
230
+ this.tasks.delete(row.id); // cascades to log_entries + task_tags
231
+ this.tags.pruneOrphans();
232
+ this.emit({ clearedSlug: row.slug });
233
+ }
234
+ // ---- logs ----
235
+ listTaskLogs(slug) {
236
+ const row = this.requireTask(slug);
237
+ return this.logs.listForTask(row.id);
238
+ }
239
+ listMasterLog(q) {
240
+ const page = Math.max(1, q.page ?? 1);
241
+ const pageSize = Math.min(MAX_PAGE_SIZE, Math.max(1, q.pageSize ?? DEFAULT_PAGE_SIZE));
242
+ const { data, total } = this.logs.listMaster({ ...q, page, pageSize });
243
+ return { data, total, page, pageSize };
244
+ }
245
+ addLog(slug, body, loggedBy) {
246
+ const task = this.requireTask(slug);
247
+ const date = this.validateDate(body.maintenance_date, 'maintenance_date');
248
+ const nowIso = this.now().toISOString();
249
+ // multi-write path (§5.6): insert + denormalization update, atomically
250
+ this.db.exec('BEGIN');
251
+ let entry;
252
+ try {
253
+ entry = this.logs.insert({
254
+ task_id: task.id,
255
+ maintenance_date: date,
256
+ runtime_hours: body.runtime_hours ?? null,
257
+ notes: body.notes ?? null,
258
+ logged_by: loggedBy,
259
+ }, nowIso);
260
+ this.recomputeDenorm(task.id);
261
+ this.db.exec('COMMIT');
262
+ }
263
+ catch (err) {
264
+ this.db.exec('ROLLBACK');
265
+ throw err;
266
+ }
267
+ this.emit();
268
+ return entry;
269
+ }
270
+ updateLog(id, body) {
271
+ const existing = this.logs.get(id);
272
+ if (!existing)
273
+ throw new ApiError(404, 'not_found', `Log entry ${id} not found`);
274
+ const date = body.maintenance_date !== undefined
275
+ ? this.validateDate(body.maintenance_date, 'maintenance_date')
276
+ : existing.maintenance_date;
277
+ this.db.exec('BEGIN');
278
+ try {
279
+ this.logs.update(id, {
280
+ maintenance_date: date,
281
+ runtime_hours: body.runtime_hours !== undefined
282
+ ? body.runtime_hours
283
+ : existing.runtime_hours,
284
+ notes: body.notes !== undefined ? body.notes : existing.notes,
285
+ });
286
+ this.recomputeDenorm(existing.task_id);
287
+ this.db.exec('COMMIT');
288
+ }
289
+ catch (err) {
290
+ this.db.exec('ROLLBACK');
291
+ throw err;
292
+ }
293
+ this.emit();
294
+ return this.logs.get(id);
295
+ }
296
+ deleteLog(id) {
297
+ const existing = this.logs.get(id);
298
+ if (!existing)
299
+ throw new ApiError(404, 'not_found', `Log entry ${id} not found`);
300
+ this.db.exec('BEGIN');
301
+ try {
302
+ this.logs.delete(id);
303
+ this.recomputeDenorm(existing.task_id);
304
+ this.db.exec('COMMIT');
305
+ }
306
+ catch (err) {
307
+ this.db.exec('ROLLBACK');
308
+ throw err;
309
+ }
310
+ this.emit();
311
+ }
312
+ // ---- tags ----
313
+ listTags() {
314
+ return this.tags.listWithCounts();
315
+ }
316
+ // ---- misc ----
317
+ runtimePaths() {
318
+ return this.tasks.runtimePaths();
319
+ }
320
+ health() {
321
+ return {
322
+ tasks: this.tasks.count(),
323
+ logEntries: this.logs.count(),
324
+ runtimePaths: this.tasks.runtimePaths(),
325
+ };
326
+ }
327
+ // ---- internals ----
328
+ /**
329
+ * §5.6: keep tasks.last_maintenance / last_runtime equal to the latest log
330
+ * entry, falling back to the creation-time seed values when no logs remain.
331
+ */
332
+ recomputeDenorm(taskId) {
333
+ const task = this.tasks.getById(taskId);
334
+ if (!task)
335
+ return;
336
+ const latest = this.logs.latestForTask(taskId);
337
+ if (latest) {
338
+ this.tasks.setLast(taskId, latest.maintenance_date, latest.runtime_hours);
339
+ }
340
+ else {
341
+ this.tasks.setLast(taskId, task.seed_last_maintenance, task.seed_last_runtime);
342
+ }
343
+ }
344
+ requireTask(slug) {
345
+ const row = this.tasks.getBySlug(slug);
346
+ if (!row)
347
+ throw new ApiError(404, 'not_found', `Task "${slug}" not found`);
348
+ return row;
349
+ }
350
+ validateIntervals(runtimeInterval, timeInterval, timeUnit) {
351
+ if (runtimeInterval != null &&
352
+ (typeof runtimeInterval !== 'number' || runtimeInterval <= 0))
353
+ throw new ApiError(400, 'invalid_interval', 'runtime_interval must be a positive number');
354
+ const hasMagnitude = timeInterval != null;
355
+ const hasUnit = timeUnit != null;
356
+ if (hasMagnitude !== hasUnit)
357
+ throw new ApiError(400, 'invalid_interval', 'time_interval and time_interval_unit must be set (or cleared) together');
358
+ if (hasMagnitude && (typeof timeInterval !== 'number' || timeInterval <= 0))
359
+ throw new ApiError(400, 'invalid_interval', 'time_interval must be a positive number');
360
+ if (hasUnit && !types_1.TIME_UNITS.includes(timeUnit))
361
+ throw new ApiError(400, 'invalid_interval', `time_interval_unit must be one of ${types_1.TIME_UNITS.join(', ')}`);
362
+ }
363
+ validateDate(value, field) {
364
+ if (!value || Number.isNaN(new Date(value).getTime()))
365
+ throw new ApiError(400, 'invalid_date', `${field} must be a valid ISO-8601 timestamp`);
366
+ return new Date(value).toISOString();
367
+ }
368
+ }
369
+ exports.MaintenanceService = MaintenanceService;
370
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NotificationManager = void 0;
4
+ exports.buildMessage = buildMessage;
5
+ const STATE_FOR_STATUS = {
6
+ overdue: 'alarm',
7
+ due_soon: 'warn',
8
+ ok: 'normal',
9
+ };
10
+ /**
11
+ * Publishes notifications.maintenance.{slug} deltas (§10.3). Only publishes
12
+ * when a task's state actually changes, to avoid delta spam.
13
+ */
14
+ class NotificationManager {
15
+ app;
16
+ pluginId;
17
+ opts;
18
+ lastState = new Map();
19
+ constructor(app, pluginId, opts) {
20
+ this.app = app;
21
+ this.pluginId = pluginId;
22
+ this.opts = opts;
23
+ }
24
+ publishAll(tasks) {
25
+ if (!this.opts.enableNotifications)
26
+ return;
27
+ for (const task of tasks) {
28
+ const state = STATE_FOR_STATUS[task.status];
29
+ if (!state) {
30
+ // unknown: publish nothing, but clear a previously-raised alarm/warn
31
+ if (this.lastState.get(task.slug) &&
32
+ this.lastState.get(task.slug) !== 'normal') {
33
+ this.send(task.slug, 'normal', `${task.name}: status unknown`);
34
+ }
35
+ continue;
36
+ }
37
+ if (this.lastState.get(task.slug) === state)
38
+ continue;
39
+ this.send(task.slug, state, buildMessage(task));
40
+ }
41
+ }
42
+ /** Clear a slug's notification (task deleted or slug renamed, §6.4). */
43
+ clear(slug) {
44
+ if (!this.opts.enableNotifications)
45
+ return;
46
+ if (this.lastState.get(slug) === undefined) {
47
+ // nothing ever published under this slug in this process — clear anyway
48
+ // in case a previous run left one behind
49
+ }
50
+ this.send(slug, 'normal', 'Maintenance notification cleared');
51
+ this.lastState.delete(slug);
52
+ }
53
+ send(slug, state, message) {
54
+ this.app.handleMessage(this.pluginId, {
55
+ updates: [
56
+ {
57
+ values: [
58
+ {
59
+ path: `notifications.maintenance.${slug}`,
60
+ value: {
61
+ state,
62
+ method: this.opts.notificationMethods,
63
+ message,
64
+ timestamp: new Date().toISOString(),
65
+ },
66
+ },
67
+ ],
68
+ },
69
+ ],
70
+ });
71
+ this.lastState.set(slug, state);
72
+ }
73
+ }
74
+ exports.NotificationManager = NotificationManager;
75
+ /**
76
+ * Human message naming the dimension that triggered the status (§10.3). When
77
+ * both dimensions share the status, the one further along (higher fraction)
78
+ * wins.
79
+ */
80
+ function buildMessage(task) {
81
+ const { status, name } = task;
82
+ if (status === 'ok')
83
+ return `${name} is up to date`;
84
+ const runtimeTriggered = task.runtime_status === status;
85
+ const timeTriggered = task.time_status === status;
86
+ let useRuntime = runtimeTriggered;
87
+ if (runtimeTriggered && timeTriggered) {
88
+ useRuntime = (task.runtime_fraction ?? 0) >= (task.time_fraction ?? 0);
89
+ }
90
+ if (status === 'overdue') {
91
+ if (useRuntime && task.remaining_runtime != null) {
92
+ return `${name} is overdue by ${round1(-task.remaining_runtime)} runtime hours`;
93
+ }
94
+ if (task.remaining_time_ms != null) {
95
+ return `${name} is overdue by ${daysText(-task.remaining_time_ms)}`;
96
+ }
97
+ return `${name} is overdue`;
98
+ }
99
+ // due_soon
100
+ if (useRuntime && task.remaining_runtime != null) {
101
+ return `${name} is due in ${round1(task.remaining_runtime)} runtime hours`;
102
+ }
103
+ if (task.remaining_time_ms != null) {
104
+ return `${name} is due in ${daysText(task.remaining_time_ms)}`;
105
+ }
106
+ return `${name} is due soon`;
107
+ }
108
+ function round1(n) {
109
+ return Math.round(n * 10) / 10;
110
+ }
111
+ function daysText(ms) {
112
+ const days = Math.max(0, Math.round(ms / 86_400_000));
113
+ return days === 1 ? '1 day' : `${days} days`;
114
+ }
115
+ //# sourceMappingURL=notifications.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../src/signalk/notifications.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RuntimeManager = void 0;
4
+ /**
5
+ * Subscribes to the union of all task runtime paths on vessels.self, keeps an
6
+ * in-memory map of the latest value, and persists it to runtime_cache so
7
+ * values survive restarts (§10.2).
8
+ *
9
+ * This is the single seconds→hours conversion boundary: SignalK runtime paths
10
+ * are seconds; everything stored/returned here is hours.
11
+ */
12
+ class RuntimeManager {
13
+ app;
14
+ db;
15
+ values = new Map();
16
+ paths = [];
17
+ unsubscribes = [];
18
+ listeners = [];
19
+ lastUpdate = null;
20
+ constructor(app, db) {
21
+ this.app = app;
22
+ this.db = db;
23
+ this.loadCache();
24
+ }
25
+ loadCache() {
26
+ const rows = this.db
27
+ .prepare(`SELECT path, value, timestamp FROM runtime_cache`)
28
+ .all();
29
+ for (const r of rows)
30
+ this.values.set(r.path, { value: r.value, timestamp: r.timestamp });
31
+ }
32
+ /** Latest runtime in hours for a path, or null if never seen. */
33
+ getHours(path) {
34
+ return this.values.get(path)?.value ?? null;
35
+ }
36
+ get subscribedPaths() {
37
+ return [...this.paths];
38
+ }
39
+ get lastUpdateAt() {
40
+ return this.lastUpdate;
41
+ }
42
+ onUpdate(fn) {
43
+ this.listeners.push(fn);
44
+ }
45
+ /** (Re)subscribe to a new set of paths; no-op if the set is unchanged. */
46
+ setPaths(paths) {
47
+ const next = [...new Set(paths)].sort();
48
+ if (next.join('\n') === this.paths.join('\n'))
49
+ return;
50
+ this.teardown();
51
+ this.paths = next;
52
+ if (!next.length)
53
+ return;
54
+ this.app.subscriptionmanager.subscribe({
55
+ context: 'vessels.self',
56
+ subscribe: next.map((path) => ({
57
+ path,
58
+ period: 5000,
59
+ policy: 'instant',
60
+ })),
61
+ }, this.unsubscribes, (err) => {
62
+ this.app.error?.(`maintenance-tracker runtime subscription error: ${err}`);
63
+ }, (delta) => this.handleDelta(delta));
64
+ }
65
+ handleDelta(delta) {
66
+ let changed = false;
67
+ for (const update of delta?.updates ?? []) {
68
+ for (const v of update?.values ?? []) {
69
+ if (typeof v?.value !== 'number' || !this.paths.includes(v.path))
70
+ continue;
71
+ const hours = v.value / 3600; // SignalK runtime is seconds (§10.2)
72
+ const timestamp = new Date().toISOString();
73
+ this.values.set(v.path, { value: hours, timestamp });
74
+ this.db
75
+ .prepare(`INSERT INTO runtime_cache (path, value, timestamp) VALUES (?, ?, ?)
76
+ ON CONFLICT(path) DO UPDATE SET value = excluded.value, timestamp = excluded.timestamp`)
77
+ .run(v.path, hours, timestamp);
78
+ this.lastUpdate = timestamp;
79
+ changed = true;
80
+ }
81
+ }
82
+ if (changed)
83
+ for (const fn of this.listeners)
84
+ fn();
85
+ }
86
+ stop() {
87
+ this.teardown();
88
+ this.paths = [];
89
+ }
90
+ teardown() {
91
+ for (const unsub of this.unsubscribes) {
92
+ try {
93
+ unsub();
94
+ }
95
+ catch {
96
+ // ignore teardown errors
97
+ }
98
+ }
99
+ this.unsubscribes = [];
100
+ }
101
+ }
102
+ exports.RuntimeManager = RuntimeManager;
103
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/signalk/runtime.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.STATUS_RANK = exports.TIME_UNITS = void 0;
4
+ exports.TIME_UNITS = ['days', 'weeks', 'months', 'years'];
5
+ exports.STATUS_RANK = {
6
+ overdue: 0,
7
+ due_soon: 1,
8
+ ok: 2,
9
+ unknown: 3,
10
+ };
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAEa,QAAA,UAAU,GAAe,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAI9D,QAAA,WAAW,GAA2B;IACjD,OAAO,EAAE,CAAC;IACV,QAAQ,EAAE,CAAC;IACX,EAAE,EAAE,CAAC;IACL,OAAO,EAAE,CAAC;CACX,CAAC"}
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file