tabletcommand-backend-models 7.4.90 → 7.4.91
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.
- package/README.md +68 -1
- package/build/index.js +2 -0
- package/build/index.js.map +1 -1
- package/build/models/status-beacon-transition.js +51 -0
- package/build/models/status-beacon-transition.js.map +1 -0
- package/build/models/status-beacon.js +174 -0
- package/build/models/status-beacon.js.map +1 -0
- package/build/test/0index.js +2 -0
- package/build/test/0index.js.map +1 -1
- package/build/test/mock.js +64 -0
- package/build/test/mock.js.map +1 -1
- package/build/test/status-beacon.js +112 -0
- package/build/test/status-beacon.js.map +1 -0
- package/build/types/status-beacon.js +3 -0
- package/build/types/status-beacon.js.map +1 -0
- package/definitions/index.d.ts +12 -0
- package/definitions/index.d.ts.map +1 -1
- package/definitions/models/status-beacon-transition.d.ts +13 -0
- package/definitions/models/status-beacon-transition.d.ts.map +1 -0
- package/definitions/models/status-beacon.d.ts +13 -0
- package/definitions/models/status-beacon.d.ts.map +1 -0
- package/definitions/test/mock.d.ts +62 -0
- package/definitions/test/mock.d.ts.map +1 -1
- package/definitions/test/status-beacon.d.ts +2 -0
- package/definitions/test/status-beacon.d.ts.map +1 -0
- package/definitions/types/status-beacon.d.ts +72 -0
- package/definitions/types/status-beacon.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +4 -0
- package/src/models/status-beacon-transition.ts +60 -0
- package/src/models/status-beacon.ts +193 -0
- package/src/test/0index.ts +2 -0
- package/src/test/mock.ts +66 -0
- package/src/test/status-beacon.ts +121 -0
- package/src/types/status-beacon.ts +90 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MongooseModule,
|
|
3
|
+
currentDate,
|
|
4
|
+
} from "../helpers";
|
|
5
|
+
import { Model } from "mongoose";
|
|
6
|
+
import {
|
|
7
|
+
StatusBeaconType,
|
|
8
|
+
QueueDepthsType,
|
|
9
|
+
TCSendHealthType,
|
|
10
|
+
WriteBackHealthType,
|
|
11
|
+
SyncHealthType,
|
|
12
|
+
} from "../types/status-beacon";
|
|
13
|
+
|
|
14
|
+
export interface StatusBeacon extends StatusBeaconType { }
|
|
15
|
+
|
|
16
|
+
export default async function StatusBeaconModule(mongoose: MongooseModule) {
|
|
17
|
+
const { Schema } = mongoose;
|
|
18
|
+
|
|
19
|
+
const QueueDepths = new Schema<QueueDepthsType>({
|
|
20
|
+
incident: { type: Number, default: 0 },
|
|
21
|
+
status: { type: Number, default: 0 },
|
|
22
|
+
vehicle: { type: Number, default: 0 },
|
|
23
|
+
total: { type: Number, default: 0 },
|
|
24
|
+
}, { _id: false, id: false });
|
|
25
|
+
|
|
26
|
+
const TCSendHealth = new Schema<TCSendHealthType>({
|
|
27
|
+
lastSuccessfulIncidentSend: { type: Date },
|
|
28
|
+
lastSuccessfulUnitStatusSend: { type: Date },
|
|
29
|
+
sendFailuresDelta: { type: Number, default: 0 },
|
|
30
|
+
lastSendError: { type: String, default: "" },
|
|
31
|
+
}, { _id: false, id: false });
|
|
32
|
+
|
|
33
|
+
const WriteBackHealth = new Schema<WriteBackHealthType>({
|
|
34
|
+
attemptsDelta: { type: Number, default: 0 },
|
|
35
|
+
failuresDelta: { type: Number, default: 0 },
|
|
36
|
+
lastSuccessfulWriteBack: { type: Date },
|
|
37
|
+
lastError: { type: String, default: "" },
|
|
38
|
+
}, { _id: false, id: false });
|
|
39
|
+
|
|
40
|
+
const SyncHealth = new Schema<SyncHealthType>({
|
|
41
|
+
lastCacheRefresh: { type: Date },
|
|
42
|
+
cacheAgeSeconds: { type: Number, default: 0 },
|
|
43
|
+
consecutiveEmptyPolls: { type: Number, default: 0 },
|
|
44
|
+
lastPollChanges: { type: Number, default: 0 },
|
|
45
|
+
incidentCacheGrowthDelta: { type: Number, default: 0 },
|
|
46
|
+
}, { _id: false, id: false });
|
|
47
|
+
|
|
48
|
+
const modelSchema = new Schema<StatusBeaconType>({
|
|
49
|
+
_id: {
|
|
50
|
+
type: Schema.Types.ObjectId,
|
|
51
|
+
auto: true,
|
|
52
|
+
},
|
|
53
|
+
departmentId: {
|
|
54
|
+
type: String,
|
|
55
|
+
default: "",
|
|
56
|
+
required: true,
|
|
57
|
+
},
|
|
58
|
+
// Identity
|
|
59
|
+
integration: {
|
|
60
|
+
type: String,
|
|
61
|
+
default: "",
|
|
62
|
+
required: true,
|
|
63
|
+
},
|
|
64
|
+
interfaceStartTime: {
|
|
65
|
+
type: Date,
|
|
66
|
+
default: currentDate,
|
|
67
|
+
},
|
|
68
|
+
// Health State
|
|
69
|
+
healthState: {
|
|
70
|
+
type: String,
|
|
71
|
+
default: "",
|
|
72
|
+
},
|
|
73
|
+
triggerReason: {
|
|
74
|
+
type: String,
|
|
75
|
+
default: "",
|
|
76
|
+
},
|
|
77
|
+
consecutiveFailures: {
|
|
78
|
+
type: Number,
|
|
79
|
+
default: 0,
|
|
80
|
+
},
|
|
81
|
+
consecutiveSuccesses: {
|
|
82
|
+
type: Number,
|
|
83
|
+
default: 0,
|
|
84
|
+
},
|
|
85
|
+
totalFailuresSinceLastHealthy: {
|
|
86
|
+
type: Number,
|
|
87
|
+
default: 0,
|
|
88
|
+
},
|
|
89
|
+
outageStartTime: {
|
|
90
|
+
type: Date,
|
|
91
|
+
},
|
|
92
|
+
// Cycle Metrics
|
|
93
|
+
pollCycle: {
|
|
94
|
+
type: Number,
|
|
95
|
+
default: 0,
|
|
96
|
+
},
|
|
97
|
+
lastPollMs: {
|
|
98
|
+
type: Number,
|
|
99
|
+
default: 0,
|
|
100
|
+
},
|
|
101
|
+
activeIncidents: {
|
|
102
|
+
type: Number,
|
|
103
|
+
default: 0,
|
|
104
|
+
},
|
|
105
|
+
activeUnits: {
|
|
106
|
+
type: Number,
|
|
107
|
+
default: 0,
|
|
108
|
+
},
|
|
109
|
+
// Data Flow Deltas
|
|
110
|
+
incidentsDelta: {
|
|
111
|
+
type: Number,
|
|
112
|
+
default: 0,
|
|
113
|
+
},
|
|
114
|
+
unitStatusDelta: {
|
|
115
|
+
type: Number,
|
|
116
|
+
default: 0,
|
|
117
|
+
},
|
|
118
|
+
// Queue Depths
|
|
119
|
+
queueDepths: {
|
|
120
|
+
type: QueueDepths,
|
|
121
|
+
default: () => ({}),
|
|
122
|
+
},
|
|
123
|
+
// Auth Token Health
|
|
124
|
+
tokenAgeSecs: {
|
|
125
|
+
type: Number,
|
|
126
|
+
},
|
|
127
|
+
tokenExpiresAt: {
|
|
128
|
+
type: Date,
|
|
129
|
+
},
|
|
130
|
+
// TC Send Health
|
|
131
|
+
tCSend: {
|
|
132
|
+
type: TCSendHealth,
|
|
133
|
+
default: () => ({}),
|
|
134
|
+
},
|
|
135
|
+
// Write-back Health
|
|
136
|
+
writeBack: {
|
|
137
|
+
type: WriteBackHealth,
|
|
138
|
+
default: () => ({}),
|
|
139
|
+
},
|
|
140
|
+
// Sync Health
|
|
141
|
+
sync: {
|
|
142
|
+
type: SyncHealth,
|
|
143
|
+
default: () => ({}),
|
|
144
|
+
},
|
|
145
|
+
// Debug & Config
|
|
146
|
+
debugPushActive: {
|
|
147
|
+
type: Boolean,
|
|
148
|
+
default: false,
|
|
149
|
+
},
|
|
150
|
+
lastConfigSave: {
|
|
151
|
+
type: Date,
|
|
152
|
+
},
|
|
153
|
+
lastConfigSaveFile: {
|
|
154
|
+
type: String,
|
|
155
|
+
default: "",
|
|
156
|
+
},
|
|
157
|
+
// Error & Version
|
|
158
|
+
lastError: {
|
|
159
|
+
type: String,
|
|
160
|
+
default: "",
|
|
161
|
+
},
|
|
162
|
+
interfaceVersion: {
|
|
163
|
+
type: String,
|
|
164
|
+
default: "",
|
|
165
|
+
},
|
|
166
|
+
cadVersion: {
|
|
167
|
+
type: String,
|
|
168
|
+
default: "",
|
|
169
|
+
},
|
|
170
|
+
unifiedVersion: {
|
|
171
|
+
type: String,
|
|
172
|
+
default: "",
|
|
173
|
+
},
|
|
174
|
+
}, {
|
|
175
|
+
autoIndex: false,
|
|
176
|
+
timestamps: true,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
modelSchema.index({ departmentId: 1, integration: 1 }, {
|
|
180
|
+
name: "departmentId_1_integration_1",
|
|
181
|
+
unique: true,
|
|
182
|
+
});
|
|
183
|
+
modelSchema.index({ healthState: 1 }, { name: "healthState_1" });
|
|
184
|
+
modelSchema.index({ triggerReason: 1 }, { name: "triggerReason_1" });
|
|
185
|
+
modelSchema.index({ "queueDepths.total": 1 }, { name: "queueDepths_total_1" });
|
|
186
|
+
modelSchema.index({ "tCSend.sendFailuresDelta": 1 }, { name: "tCSend_sendFailuresDelta_1" });
|
|
187
|
+
modelSchema.index({ "writeBack.failuresDelta": 1 }, { name: "writeBack_failuresDelta_1" });
|
|
188
|
+
modelSchema.index({ "sync.consecutiveEmptyPolls": 1 }, { name: "sync_consecutiveEmptyPolls_1" });
|
|
189
|
+
|
|
190
|
+
return mongoose.model<StatusBeacon>("StatusBeacon", modelSchema, "massive_status_beacon", { overwriteModels: true });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export interface StatusBeaconModel extends Model<StatusBeacon> { }
|
package/src/test/0index.ts
CHANGED
|
@@ -67,6 +67,8 @@ describe(" Models", function() {
|
|
|
67
67
|
assert.isFunction(models.RemoteLogStream, "Missing RemoteLogStream");
|
|
68
68
|
assert.isFunction(models.Session, "Missing Session");
|
|
69
69
|
assert.isFunction(models.SAML, "Missing SAML");
|
|
70
|
+
assert.isFunction(models.StatusBeacon, "Missing StatusBeacon");
|
|
71
|
+
assert.isFunction(models.StatusBeaconTransition, "Missing StatusBeaconTransition");
|
|
70
72
|
assert.isFunction(models.SMSLog, "Missing SMSLog");
|
|
71
73
|
assert.isFunction(models.SMTPUnhandled, "Missing SMTPUnhandled");
|
|
72
74
|
assert.isFunction(models.Template, "Missing Template");
|
package/src/test/mock.ts
CHANGED
|
@@ -1504,6 +1504,70 @@ export default function mockModule(dependencies: { mongoose: Mongoose; }) {
|
|
|
1504
1504
|
sendNotification: false
|
|
1505
1505
|
};
|
|
1506
1506
|
|
|
1507
|
+
const statusBeacon = {
|
|
1508
|
+
_id: new mongoose.Types.ObjectId(),
|
|
1509
|
+
departmentId,
|
|
1510
|
+
integration: "test-cad-integration",
|
|
1511
|
+
interfaceStartTime: new Date(),
|
|
1512
|
+
healthState: "healthy",
|
|
1513
|
+
triggerReason: "poll_success",
|
|
1514
|
+
consecutiveFailures: 0,
|
|
1515
|
+
consecutiveSuccesses: 5,
|
|
1516
|
+
totalFailuresSinceLastHealthy: 0,
|
|
1517
|
+
outageStartTime: undefined,
|
|
1518
|
+
pollCycle: 42,
|
|
1519
|
+
lastPollMs: 350,
|
|
1520
|
+
activeIncidents: 3,
|
|
1521
|
+
activeUnits: 12,
|
|
1522
|
+
incidentsDelta: 1,
|
|
1523
|
+
unitStatusDelta: 2,
|
|
1524
|
+
queueDepths: {
|
|
1525
|
+
incident: 0,
|
|
1526
|
+
status: 0,
|
|
1527
|
+
vehicle: 0,
|
|
1528
|
+
total: 0,
|
|
1529
|
+
},
|
|
1530
|
+
tokenAgeSecs: 1800,
|
|
1531
|
+
tokenExpiresAt: new Date(),
|
|
1532
|
+
tCSend: {
|
|
1533
|
+
lastSuccessfulIncidentSend: new Date(),
|
|
1534
|
+
lastSuccessfulUnitStatusSend: new Date(),
|
|
1535
|
+
sendFailuresDelta: 0,
|
|
1536
|
+
lastSendError: "",
|
|
1537
|
+
},
|
|
1538
|
+
writeBack: {
|
|
1539
|
+
attemptsDelta: 0,
|
|
1540
|
+
failuresDelta: 0,
|
|
1541
|
+
lastSuccessfulWriteBack: new Date(),
|
|
1542
|
+
lastError: "",
|
|
1543
|
+
},
|
|
1544
|
+
sync: {
|
|
1545
|
+
lastCacheRefresh: new Date(),
|
|
1546
|
+
cacheAgeSeconds: 30,
|
|
1547
|
+
consecutiveEmptyPolls: 0,
|
|
1548
|
+
lastPollChanges: 2,
|
|
1549
|
+
incidentCacheGrowthDelta: 1,
|
|
1550
|
+
},
|
|
1551
|
+
debugPushActive: false,
|
|
1552
|
+
lastConfigSave: new Date(),
|
|
1553
|
+
lastConfigSaveFile: "config-v1.json",
|
|
1554
|
+
lastError: "",
|
|
1555
|
+
interfaceVersion: "1.2.3",
|
|
1556
|
+
cadVersion: "4.5.6",
|
|
1557
|
+
unifiedVersion: "7.8.9",
|
|
1558
|
+
};
|
|
1559
|
+
|
|
1560
|
+
const statusBeaconTransition = {
|
|
1561
|
+
_id: new mongoose.Types.ObjectId(),
|
|
1562
|
+
departmentId,
|
|
1563
|
+
integration: "test-cad-integration",
|
|
1564
|
+
triggerReason: "consecutive_failures",
|
|
1565
|
+
healthState: "degraded",
|
|
1566
|
+
consecutiveFailures: 3,
|
|
1567
|
+
totalFailuresSinceLastHealthy: 5,
|
|
1568
|
+
lastError: "connection timeout",
|
|
1569
|
+
};
|
|
1570
|
+
|
|
1507
1571
|
const validationReport = {
|
|
1508
1572
|
_id: new mongoose.Types.ObjectId(),
|
|
1509
1573
|
departmentId: new mongoose.Types.ObjectId("56131f724143487a10000001"),
|
|
@@ -1601,6 +1665,8 @@ export default function mockModule(dependencies: { mongoose: Mongoose; }) {
|
|
|
1601
1665
|
releaseNote,
|
|
1602
1666
|
session,
|
|
1603
1667
|
saml,
|
|
1668
|
+
statusBeacon,
|
|
1669
|
+
statusBeaconTransition,
|
|
1604
1670
|
template,
|
|
1605
1671
|
user,
|
|
1606
1672
|
userDevice,
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { assert } from "chai";
|
|
2
|
+
import { describe, it, beforeEach, afterEach } from "node:test";
|
|
3
|
+
import * as m from "../index";
|
|
4
|
+
import * as config from "./config";
|
|
5
|
+
import mockModule from "./mock";
|
|
6
|
+
|
|
7
|
+
describe("StatusBeacon", function() {
|
|
8
|
+
let models: m.BackendModels, mongoose: m.MongooseModule;
|
|
9
|
+
let testItem: Partial<m.StatusBeacon>;
|
|
10
|
+
beforeEach(async function() {
|
|
11
|
+
const c = await m.connect(config.url);
|
|
12
|
+
models = c.models;
|
|
13
|
+
mongoose = c.mongoose;
|
|
14
|
+
|
|
15
|
+
const mock = mockModule({ mongoose });
|
|
16
|
+
testItem = mock.statusBeacon;
|
|
17
|
+
await mock.beforeEach();
|
|
18
|
+
});
|
|
19
|
+
afterEach(async function() {
|
|
20
|
+
await mongoose.disconnect();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("is saved", async function() {
|
|
24
|
+
const item = new models.StatusBeacon(testItem);
|
|
25
|
+
const sut = await item.save();
|
|
26
|
+
|
|
27
|
+
assert.isNotNull(sut._id);
|
|
28
|
+
assert.equal(testItem.departmentId, sut.departmentId);
|
|
29
|
+
assert.equal(testItem.integration, sut.integration);
|
|
30
|
+
assert.equal(testItem.healthState, sut.healthState);
|
|
31
|
+
assert.equal(testItem.triggerReason, sut.triggerReason);
|
|
32
|
+
assert.equal(testItem.consecutiveFailures, sut.consecutiveFailures);
|
|
33
|
+
assert.equal(testItem.consecutiveSuccesses, sut.consecutiveSuccesses);
|
|
34
|
+
assert.equal(testItem.totalFailuresSinceLastHealthy, sut.totalFailuresSinceLastHealthy);
|
|
35
|
+
assert.equal(testItem.pollCycle, sut.pollCycle);
|
|
36
|
+
assert.equal(testItem.lastPollMs, sut.lastPollMs);
|
|
37
|
+
assert.equal(testItem.activeIncidents, sut.activeIncidents);
|
|
38
|
+
assert.equal(testItem.activeUnits, sut.activeUnits);
|
|
39
|
+
assert.equal(testItem.incidentsDelta, sut.incidentsDelta);
|
|
40
|
+
assert.equal(testItem.unitStatusDelta, sut.unitStatusDelta);
|
|
41
|
+
assert.equal(testItem.tokenAgeSecs, sut.tokenAgeSecs);
|
|
42
|
+
assert.equal(testItem.debugPushActive, sut.debugPushActive);
|
|
43
|
+
assert.equal(testItem.lastConfigSaveFile, sut.lastConfigSaveFile);
|
|
44
|
+
assert.equal(testItem.lastError, sut.lastError);
|
|
45
|
+
assert.equal(testItem.interfaceVersion, sut.interfaceVersion);
|
|
46
|
+
assert.equal(testItem.cadVersion, sut.cadVersion);
|
|
47
|
+
assert.equal(testItem.unifiedVersion, sut.unifiedVersion);
|
|
48
|
+
assert.isNotNull(sut.createdAt);
|
|
49
|
+
assert.isNotNull(sut.updatedAt);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("saves nested queueDepths", async function() {
|
|
53
|
+
const item = new models.StatusBeacon(testItem);
|
|
54
|
+
const sut = await item.save();
|
|
55
|
+
|
|
56
|
+
assert.equal(testItem.queueDepths?.incident, sut.queueDepths.incident);
|
|
57
|
+
assert.equal(testItem.queueDepths?.status, sut.queueDepths.status);
|
|
58
|
+
assert.equal(testItem.queueDepths?.vehicle, sut.queueDepths.vehicle);
|
|
59
|
+
assert.equal(testItem.queueDepths?.total, sut.queueDepths.total);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("saves nested tCSend health", async function() {
|
|
63
|
+
const item = new models.StatusBeacon(testItem);
|
|
64
|
+
const sut = await item.save();
|
|
65
|
+
|
|
66
|
+
assert.equal(testItem.tCSend?.sendFailuresDelta, sut.tCSend.sendFailuresDelta);
|
|
67
|
+
assert.equal(testItem.tCSend?.lastSendError, sut.tCSend.lastSendError);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("saves nested writeBack health", async function() {
|
|
71
|
+
const item = new models.StatusBeacon(testItem);
|
|
72
|
+
const sut = await item.save();
|
|
73
|
+
|
|
74
|
+
assert.equal(testItem.writeBack?.attemptsDelta, sut.writeBack.attemptsDelta);
|
|
75
|
+
assert.equal(testItem.writeBack?.failuresDelta, sut.writeBack.failuresDelta);
|
|
76
|
+
assert.equal(testItem.writeBack?.lastError, sut.writeBack.lastError);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("saves nested sync health", async function() {
|
|
80
|
+
const item = new models.StatusBeacon(testItem);
|
|
81
|
+
const sut = await item.save();
|
|
82
|
+
|
|
83
|
+
assert.equal(testItem.sync?.cacheAgeSeconds, sut.sync.cacheAgeSeconds);
|
|
84
|
+
assert.equal(testItem.sync?.consecutiveEmptyPolls, sut.sync.consecutiveEmptyPolls);
|
|
85
|
+
assert.equal(testItem.sync?.lastPollChanges, sut.sync.lastPollChanges);
|
|
86
|
+
assert.equal(testItem.sync?.incidentCacheGrowthDelta, sut.sync.incidentCacheGrowthDelta);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe("StatusBeaconTransition", function() {
|
|
91
|
+
let models: m.BackendModels, mongoose: m.MongooseModule;
|
|
92
|
+
let testItem: Partial<m.StatusBeaconTransition>;
|
|
93
|
+
beforeEach(async function() {
|
|
94
|
+
const c = await m.connect(config.url);
|
|
95
|
+
models = c.models;
|
|
96
|
+
mongoose = c.mongoose;
|
|
97
|
+
|
|
98
|
+
const mock = mockModule({ mongoose });
|
|
99
|
+
testItem = mock.statusBeaconTransition;
|
|
100
|
+
await mock.beforeEach();
|
|
101
|
+
});
|
|
102
|
+
afterEach(async function() {
|
|
103
|
+
await mongoose.disconnect();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("is saved", async function() {
|
|
107
|
+
const item = new models.StatusBeaconTransition(testItem);
|
|
108
|
+
const sut = await item.save();
|
|
109
|
+
|
|
110
|
+
assert.isNotNull(sut._id);
|
|
111
|
+
assert.equal(testItem.departmentId, sut.departmentId);
|
|
112
|
+
assert.equal(testItem.integration, sut.integration);
|
|
113
|
+
assert.equal(testItem.triggerReason, sut.triggerReason);
|
|
114
|
+
assert.equal(testItem.healthState, sut.healthState);
|
|
115
|
+
assert.equal(testItem.consecutiveFailures, sut.consecutiveFailures);
|
|
116
|
+
assert.equal(testItem.totalFailuresSinceLastHealthy, sut.totalFailuresSinceLastHealthy);
|
|
117
|
+
assert.equal(testItem.lastError, sut.lastError);
|
|
118
|
+
assert.isNotNull(sut.createdAt);
|
|
119
|
+
assert.isNotNull(sut.updatedAt);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Types } from "mongoose";
|
|
2
|
+
|
|
3
|
+
export interface QueueDepthsType {
|
|
4
|
+
incident: number;
|
|
5
|
+
status: number;
|
|
6
|
+
vehicle: number;
|
|
7
|
+
total: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface TCSendHealthType {
|
|
11
|
+
lastSuccessfulIncidentSend?: Date;
|
|
12
|
+
lastSuccessfulUnitStatusSend?: Date;
|
|
13
|
+
sendFailuresDelta: number;
|
|
14
|
+
lastSendError: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface WriteBackHealthType {
|
|
18
|
+
attemptsDelta: number;
|
|
19
|
+
failuresDelta: number;
|
|
20
|
+
lastSuccessfulWriteBack?: Date;
|
|
21
|
+
lastError: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface SyncHealthType {
|
|
25
|
+
lastCacheRefresh?: Date;
|
|
26
|
+
cacheAgeSeconds: number;
|
|
27
|
+
consecutiveEmptyPolls: number;
|
|
28
|
+
lastPollChanges: number;
|
|
29
|
+
incidentCacheGrowthDelta: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface StatusBeaconType {
|
|
33
|
+
_id: Types.ObjectId;
|
|
34
|
+
departmentId: string;
|
|
35
|
+
// Identity
|
|
36
|
+
integration: string;
|
|
37
|
+
interfaceStartTime: Date; // UTC time the integration service process started; never resets — use for uptime
|
|
38
|
+
// Health State
|
|
39
|
+
healthState: string;
|
|
40
|
+
triggerReason: string;
|
|
41
|
+
consecutiveFailures: number;
|
|
42
|
+
consecutiveSuccesses: number;
|
|
43
|
+
totalFailuresSinceLastHealthy: number;
|
|
44
|
+
outageStartTime?: Date; // UTC time the current outage began; absent when healthy
|
|
45
|
+
// Cycle Metrics
|
|
46
|
+
pollCycle: number;
|
|
47
|
+
lastPollMs: number;
|
|
48
|
+
activeIncidents: number;
|
|
49
|
+
activeUnits: number;
|
|
50
|
+
// Data Flow Deltas
|
|
51
|
+
incidentsDelta: number;
|
|
52
|
+
unitStatusDelta: number;
|
|
53
|
+
// Queue Depths
|
|
54
|
+
queueDepths: QueueDepthsType;
|
|
55
|
+
// Auth Token Health (Bearer auth only; null otherwise)
|
|
56
|
+
tokenAgeSecs?: number;
|
|
57
|
+
tokenExpiresAt?: Date;
|
|
58
|
+
// TC Send Health
|
|
59
|
+
tCSend: TCSendHealthType;
|
|
60
|
+
// Write-back Health
|
|
61
|
+
writeBack: WriteBackHealthType;
|
|
62
|
+
// Sync Health
|
|
63
|
+
sync: SyncHealthType;
|
|
64
|
+
// Debug & Config
|
|
65
|
+
debugPushActive: boolean;
|
|
66
|
+
lastConfigSave?: Date;
|
|
67
|
+
lastConfigSaveFile: string;
|
|
68
|
+
// Error & Version
|
|
69
|
+
lastError: string;
|
|
70
|
+
interfaceVersion: string;
|
|
71
|
+
cadVersion: string;
|
|
72
|
+
unifiedVersion: string;
|
|
73
|
+
// System (managed by Mongoose timestamps)
|
|
74
|
+
createdAt: Date;
|
|
75
|
+
updatedAt: Date;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface StatusBeaconTransitionType {
|
|
79
|
+
_id: Types.ObjectId;
|
|
80
|
+
departmentId: string;
|
|
81
|
+
integration: string;
|
|
82
|
+
triggerReason: string;
|
|
83
|
+
healthState: string;
|
|
84
|
+
consecutiveFailures: number;
|
|
85
|
+
totalFailuresSinceLastHealthy: number;
|
|
86
|
+
lastError: string;
|
|
87
|
+
// System (managed by Mongoose timestamps)
|
|
88
|
+
createdAt: Date;
|
|
89
|
+
updatedAt: Date;
|
|
90
|
+
}
|