@justair/justair-library 4.8.11 → 4.8.13

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 (35) hide show
  1. package/.github/workflows/publish.yml +28 -0
  2. package/README +146 -146
  3. package/package.json +27 -27
  4. package/src/config/db.js +116 -116
  5. package/src/config/logger.js +143 -143
  6. package/src/index.js +116 -116
  7. package/src/models/admin.js +27 -27
  8. package/src/models/alerts.js +219 -219
  9. package/src/models/announcements.js +31 -31
  10. package/src/models/apiKey.js +22 -22
  11. package/src/models/configurations.js +17 -17
  12. package/src/models/contexts.js +13 -13
  13. package/src/models/dataCompleteness.js +35 -35
  14. package/src/models/events.js +128 -128
  15. package/src/models/features.js +14 -14
  16. package/src/models/jobs.js +43 -43
  17. package/src/models/lightmonitors.js +30 -30
  18. package/src/models/measurements.js +263 -263
  19. package/src/models/monitorRequests.js +25 -25
  20. package/src/models/monitorSuppliers.js +49 -49
  21. package/src/models/monitors.js +394 -394
  22. package/src/models/networkMetrics.js +42 -42
  23. package/src/models/organizations.js +97 -97
  24. package/src/models/parameters.js +11 -11
  25. package/src/models/referenceMonitorInfo.js +18 -18
  26. package/src/models/tests/admin.test.js +42 -42
  27. package/src/models/tests/configurations.test.js +44 -44
  28. package/src/models/tests/measurements.test.js +46 -46
  29. package/src/models/tests/monitorRequests.test.js +46 -46
  30. package/src/models/tests/monitors.test.js +62 -62
  31. package/src/models/tests/organizations.test.js +51 -51
  32. package/src/models/tests/users.test.js +54 -54
  33. package/src/models/usageMetrics.js +28 -28
  34. package/src/models/users.js +55 -55
  35. package/tsconfig.json +10 -10
@@ -1,35 +1,35 @@
1
- import mongoose from "mongoose";
2
-
3
- const dataCompletenessSchema = mongoose.Schema(
4
- {
5
- monitorId: { type: mongoose.Types.ObjectId, ref: "Monitors" },
6
- supplierId: { type: mongoose.Types.ObjectId, ref: "MonitorSuppliers" },
7
- parameter: String,
8
- count: Number,
9
- threshold: Number,
10
- completeness: Number, // percent 0–100
11
- measurementsStartTime: Date,
12
- measurementsEndTime: Date,
13
- flags: Object
14
- },
15
- { timestamps: true }
16
- );
17
- const DataCompleteness = mongoose.model(
18
- "DataCompleteness",
19
- dataCompletenessSchema
20
- );
21
-
22
-
23
- dataCompletenessSchema.index({
24
- monitorId: 1,
25
- parameter: 1,
26
- measurementsStartTime: 1
27
- });
28
-
29
- dataCompletenessSchema.index({
30
- monitorId: 1,
31
- measurementsStartTime: 1,
32
- flags: 1
33
- });
34
-
35
- export { dataCompletenessSchema, DataCompleteness };
1
+ import mongoose from "mongoose";
2
+
3
+ const dataCompletenessSchema = mongoose.Schema(
4
+ {
5
+ monitorId: { type: mongoose.Types.ObjectId, ref: "Monitors" },
6
+ supplierId: { type: mongoose.Types.ObjectId, ref: "MonitorSuppliers" },
7
+ parameter: String,
8
+ count: Number,
9
+ threshold: Number,
10
+ completeness: Number, // percent 0–100
11
+ measurementsStartTime: Date,
12
+ measurementsEndTime: Date,
13
+ flags: Object
14
+ },
15
+ { timestamps: true }
16
+ );
17
+ const DataCompleteness = mongoose.model(
18
+ "DataCompleteness",
19
+ dataCompletenessSchema
20
+ );
21
+
22
+
23
+ dataCompletenessSchema.index({
24
+ monitorId: 1,
25
+ parameter: 1,
26
+ measurementsStartTime: 1
27
+ });
28
+
29
+ dataCompletenessSchema.index({
30
+ monitorId: 1,
31
+ measurementsStartTime: 1,
32
+ flags: 1
33
+ });
34
+
35
+ export { dataCompletenessSchema, DataCompleteness };
@@ -1,128 +1,128 @@
1
- import mongoose, {Types} from "mongoose";
2
-
3
- // Events Audit Schema
4
- const eventsAuditSchema = mongoose.Schema(
5
- {
6
- monitorId: { type: mongoose.Types.ObjectId, ref: "Monitors" },
7
- parameter: {
8
- type: String,
9
- enum: ["AQI", "PID", "AQI-Daily"],
10
- },
11
- values: Object,
12
- alertLevels: Object,
13
- currentMonitorState: {
14
- type: String,
15
- enum: ["Collocation", "Deployed", "Maintenance", "Pending Deployment"],
16
- },
17
- deletedAt: { type: Date, default: null },
18
- },
19
- {
20
- timestamps: true,
21
- }
22
- );
23
-
24
- const EventsAudit = mongoose.model("EventsAudit", eventsAuditSchema);
25
-
26
- // Events Schema
27
- const eventsSchema = mongoose.Schema(
28
- {
29
- monitorId: { type: mongoose.Types.ObjectId, ref: "Monitors" },
30
- parameter: {
31
- type: String,
32
- enum: ["AQI", "PID"],
33
- },
34
- values: Object,
35
- alertLevels: Object,
36
- currentMonitorState: {
37
- type: String,
38
- enum: ["Collocation", "Deployed", "Maintenance", "Pending Deployment"],
39
- },
40
- pausedParameters: [String],
41
- originalId: { type: mongoose.Types.ObjectId },
42
- },
43
- {
44
- timestamps: true,
45
- },
46
- );
47
-
48
- // Primary lookup pattern from monitors - for $lookup operations
49
- eventsSchema.index({ monitorId: 1, createdAt: -1 });
50
- // Date range filtering index
51
- eventsSchema.index({ monitorId: 1, updatedAt: -1 });
52
-
53
- eventsSchema.index({ parameter: 1 });
54
-
55
- // Pre-hook to log single document deletions
56
- eventsSchema.pre("findOneAndDelete", async function () {
57
- const docToDelete = await this.model.findOne(this.getFilter());
58
- if (docToDelete) {
59
- console.log("Logging findOneAndDelete to events audit", docToDelete);
60
- const auditLog = new EventsAudit({
61
- ...docToDelete.toObject(),
62
- deletedAt: new Date(),
63
- });
64
- await auditLog.save();
65
- }
66
- });
67
-
68
- // Pre-hook to log multiple document deletions
69
- eventsSchema.pre("deleteMany", async function () {
70
- const docsToDelete = await this.model.find(this.getFilter()).lean();
71
- if (docsToDelete.length) {
72
- console.log(`Logging ${docsToDelete.length} documents to events audit`);
73
- const auditLogs = docsToDelete.map((doc) => ({
74
- ...doc,
75
- originalId: doc._id, // store reference to original _id
76
- _id: undefined, // let Mongo generate new _id
77
- deletedAt: new Date(),
78
- }));
79
- await EventsAudit.insertMany(auditLogs);
80
- }
81
- });
82
-
83
- // Pre-hook to log a single document deletion (for deleteOne)
84
- eventsSchema.pre("deleteOne", async function () {
85
- const docToDelete = await this.model.findOne(this.getFilter()).lean();
86
- if (docToDelete) {
87
- console.log("Logging deleteOne to events audit", docToDelete);
88
- const auditLog = new EventsAudit({
89
- ...docToDelete,
90
- originalId: docToDelete._id, // store reference to original _id
91
- _id: undefined, // let Mongo generate new _id
92
- deletedAt: new Date(),
93
- });
94
- await auditLog.save();
95
- }
96
- });
97
-
98
- // Pre-hook to log single document updates
99
- eventsSchema.pre("findOneAndUpdate", async function () {
100
- const docToUpdate = await this.model.findOne(this.getFilter()).lean();
101
- if (docToUpdate) {
102
- console.log("Logging findOneAndUpdate to events audit", docToUpdate);
103
- const auditLog = new EventsAudit({
104
- ...docToUpdate,
105
- deletedAt: null, // Not deleted
106
- });
107
- await auditLog.save();
108
- }
109
- });
110
-
111
- // Pre-hook to log multiple document updates
112
- eventsSchema.pre("updateMany", async function () {
113
- const docsToUpdate = await this.model.find(this.getFilter()).lean();
114
- if (docsToUpdate.length) {
115
- console.log(`Logging ${docsToUpdate.length} documents to events audit`);
116
- const auditLogs = docsToUpdate.map((doc) => ({
117
- ...doc,
118
- originalId: doc._id, // store reference to original _id
119
- _id: undefined, // let Mongo generate new _id
120
- deletedAt: null, // Not deleted
121
- }));
122
- await EventsAudit.insertMany(auditLogs);
123
- }
124
- });
125
-
126
- const Events = mongoose.model("Events", eventsSchema);
127
-
128
- export { eventsSchema, Events, EventsAudit, eventsAuditSchema };
1
+ import mongoose, {Types} from "mongoose";
2
+
3
+ // Events Audit Schema
4
+ const eventsAuditSchema = mongoose.Schema(
5
+ {
6
+ monitorId: { type: mongoose.Types.ObjectId, ref: "Monitors" },
7
+ parameter: {
8
+ type: String,
9
+ enum: ["AQI", "PID", "AQI-Daily"],
10
+ },
11
+ values: Object,
12
+ alertLevels: Object,
13
+ currentMonitorState: {
14
+ type: String,
15
+ enum: ["Collocation", "Deployed", "Maintenance", "Pending Deployment"],
16
+ },
17
+ deletedAt: { type: Date, default: null },
18
+ },
19
+ {
20
+ timestamps: true,
21
+ }
22
+ );
23
+
24
+ const EventsAudit = mongoose.model("EventsAudit", eventsAuditSchema);
25
+
26
+ // Events Schema
27
+ const eventsSchema = mongoose.Schema(
28
+ {
29
+ monitorId: { type: mongoose.Types.ObjectId, ref: "Monitors" },
30
+ parameter: {
31
+ type: String,
32
+ enum: ["AQI", "PID"],
33
+ },
34
+ values: Object,
35
+ alertLevels: Object,
36
+ currentMonitorState: {
37
+ type: String,
38
+ enum: ["Collocation", "Deployed", "Maintenance", "Pending Deployment"],
39
+ },
40
+ pausedParameters: [String],
41
+ originalId: { type: mongoose.Types.ObjectId },
42
+ },
43
+ {
44
+ timestamps: true,
45
+ },
46
+ );
47
+
48
+ // Primary lookup pattern from monitors - for $lookup operations
49
+ eventsSchema.index({ monitorId: 1, createdAt: -1 });
50
+ // Date range filtering index
51
+ eventsSchema.index({ monitorId: 1, updatedAt: -1 });
52
+
53
+ eventsSchema.index({ parameter: 1 });
54
+
55
+ // Pre-hook to log single document deletions
56
+ eventsSchema.pre("findOneAndDelete", async function () {
57
+ const docToDelete = await this.model.findOne(this.getFilter());
58
+ if (docToDelete) {
59
+ console.log("Logging findOneAndDelete to events audit", docToDelete);
60
+ const auditLog = new EventsAudit({
61
+ ...docToDelete.toObject(),
62
+ deletedAt: new Date(),
63
+ });
64
+ await auditLog.save();
65
+ }
66
+ });
67
+
68
+ // Pre-hook to log multiple document deletions
69
+ eventsSchema.pre("deleteMany", async function () {
70
+ const docsToDelete = await this.model.find(this.getFilter()).lean();
71
+ if (docsToDelete.length) {
72
+ console.log(`Logging ${docsToDelete.length} documents to events audit`);
73
+ const auditLogs = docsToDelete.map((doc) => ({
74
+ ...doc,
75
+ originalId: doc._id, // store reference to original _id
76
+ _id: undefined, // let Mongo generate new _id
77
+ deletedAt: new Date(),
78
+ }));
79
+ await EventsAudit.insertMany(auditLogs);
80
+ }
81
+ });
82
+
83
+ // Pre-hook to log a single document deletion (for deleteOne)
84
+ eventsSchema.pre("deleteOne", async function () {
85
+ const docToDelete = await this.model.findOne(this.getFilter()).lean();
86
+ if (docToDelete) {
87
+ console.log("Logging deleteOne to events audit", docToDelete);
88
+ const auditLog = new EventsAudit({
89
+ ...docToDelete,
90
+ originalId: docToDelete._id, // store reference to original _id
91
+ _id: undefined, // let Mongo generate new _id
92
+ deletedAt: new Date(),
93
+ });
94
+ await auditLog.save();
95
+ }
96
+ });
97
+
98
+ // Pre-hook to log single document updates
99
+ eventsSchema.pre("findOneAndUpdate", async function () {
100
+ const docToUpdate = await this.model.findOne(this.getFilter()).lean();
101
+ if (docToUpdate) {
102
+ console.log("Logging findOneAndUpdate to events audit", docToUpdate);
103
+ const auditLog = new EventsAudit({
104
+ ...docToUpdate,
105
+ deletedAt: null, // Not deleted
106
+ });
107
+ await auditLog.save();
108
+ }
109
+ });
110
+
111
+ // Pre-hook to log multiple document updates
112
+ eventsSchema.pre("updateMany", async function () {
113
+ const docsToUpdate = await this.model.find(this.getFilter()).lean();
114
+ if (docsToUpdate.length) {
115
+ console.log(`Logging ${docsToUpdate.length} documents to events audit`);
116
+ const auditLogs = docsToUpdate.map((doc) => ({
117
+ ...doc,
118
+ originalId: doc._id, // store reference to original _id
119
+ _id: undefined, // let Mongo generate new _id
120
+ deletedAt: null, // Not deleted
121
+ }));
122
+ await EventsAudit.insertMany(auditLogs);
123
+ }
124
+ });
125
+
126
+ const Events = mongoose.model("Events", eventsSchema);
127
+
128
+ export { eventsSchema, Events, EventsAudit, eventsAuditSchema };
@@ -1,14 +1,14 @@
1
- import mongoose from "mongoose";
2
-
3
- const featuresSchema = mongoose.Schema(
4
- {
5
- name: String,
6
- },
7
- {
8
- timestamps: true,
9
- }
10
- );
11
-
12
- const Features = mongoose.model("Features", featuresSchema);
13
-
14
- export { featuresSchema, Features };
1
+ import mongoose from "mongoose";
2
+
3
+ const featuresSchema = mongoose.Schema(
4
+ {
5
+ name: String,
6
+ },
7
+ {
8
+ timestamps: true,
9
+ }
10
+ );
11
+
12
+ const Features = mongoose.model("Features", featuresSchema);
13
+
14
+ export { featuresSchema, Features };
@@ -1,43 +1,43 @@
1
- import mongoose from "mongoose";
2
-
3
- const jobsSchema = mongoose.Schema(
4
- {
5
- requestorId: { type: mongoose.Types.ObjectId, ref: "Admin" },
6
- requestorEmail: String,
7
- category: {
8
- type: String,
9
- enum: [
10
- "Truck Detection",
11
- "Backfill Monitor Data",
12
- "AQI Network Summary",
13
- "Multi Monitor Data Pull",
14
- "Multi Monitor Average AQI Data Pull",
15
- ],
16
- },
17
- resourceURL: String,
18
- publicResourceURL: String,
19
- resourceMetaData: Object,
20
- resultData: { type: mongoose.Schema.Types.Mixed, default: {} },
21
- jobStatus: {
22
- type: String,
23
- enum: ["New", "In-Progress", "Complete", "Cancelled", "Failed"],
24
- },
25
- jobStatusHistory: [Object],
26
- sharedWith: [{ type: mongoose.Types.ObjectId, ref: "Admin" }],
27
- },
28
- {
29
- timestamps: true,
30
- }
31
- );
32
-
33
- const Jobs = mongoose.model("Jobs", jobsSchema);
34
-
35
- // Exclude specific categories efficiently with timestamp ordering
36
- jobsSchema.index({ requestorId: 1, category: 1, createdAt: -1 });
37
- // Monitor-based job lookups (if monitorId field exists in resourceMetaData)
38
- // Note: This may need to be adjusted based on actual schema structure
39
- jobsSchema.index({ "resourceMetaData.monitorId": 1, updatedAt: -1 });
40
-
41
- jobsSchema.index({ jobStatus: 1 });
42
-
43
- export { jobsSchema, Jobs };
1
+ import mongoose from "mongoose";
2
+
3
+ const jobsSchema = mongoose.Schema(
4
+ {
5
+ requestorId: { type: mongoose.Types.ObjectId, ref: "Admin" },
6
+ requestorEmail: String,
7
+ category: {
8
+ type: String,
9
+ enum: [
10
+ "Truck Detection",
11
+ "Backfill Monitor Data",
12
+ "AQI Network Summary",
13
+ "Multi Monitor Data Pull",
14
+ "Multi Monitor Average AQI Data Pull",
15
+ ],
16
+ },
17
+ resourceURL: String,
18
+ publicResourceURL: String,
19
+ resourceMetaData: Object,
20
+ resultData: { type: mongoose.Schema.Types.Mixed, default: {} },
21
+ jobStatus: {
22
+ type: String,
23
+ enum: ["New", "In-Progress", "Complete", "Cancelled", "Failed"],
24
+ },
25
+ jobStatusHistory: [Object],
26
+ sharedWith: [{ type: mongoose.Types.ObjectId, ref: "Admin" }],
27
+ },
28
+ {
29
+ timestamps: true,
30
+ }
31
+ );
32
+
33
+ const Jobs = mongoose.model("Jobs", jobsSchema);
34
+
35
+ // Exclude specific categories efficiently with timestamp ordering
36
+ jobsSchema.index({ requestorId: 1, category: 1, createdAt: -1 });
37
+ // Monitor-based job lookups (if monitorId field exists in resourceMetaData)
38
+ // Note: This may need to be adjusted based on actual schema structure
39
+ jobsSchema.index({ "resourceMetaData.monitorId": 1, updatedAt: -1 });
40
+
41
+ jobsSchema.index({ jobStatus: 1 });
42
+
43
+ export { jobsSchema, Jobs };
@@ -1,30 +1,30 @@
1
- import mongoose from "mongoose";
2
-
3
- const lightMonitorSchema = mongoose.Schema(
4
- {
5
- monitorId: { type: mongoose.Types.ObjectId, ref: "Monitors" },
6
- currentColor: { type: String, default: "16000" },
7
- isActive: { type: Boolean, default: false },
8
- configuration: {
9
- hueUsername: { type: String },
10
- clientId: { type: String, required: true },
11
- clientSecret: { type: String, required: true },
12
- lightId: { type: String, required: true },
13
- accessTokenInfo: Object,
14
- accessTokenCapturedAt: { type: Date },
15
- refreshTokenInfo: Object,
16
- refreshTokenCapturedAt: { type: Date },
17
- hueCode: { type: String, required: true },
18
- hueCodeHistory: [Object],
19
- },
20
- },
21
- {
22
- timestamps: true,
23
- }
24
- );
25
-
26
- lightMonitorSchema.index({ monitorId: 1 });
27
-
28
- const LightMonitors = mongoose.model("LightMonitor", lightMonitorSchema);
29
-
30
- export { lightMonitorSchema, LightMonitors };
1
+ import mongoose from "mongoose";
2
+
3
+ const lightMonitorSchema = mongoose.Schema(
4
+ {
5
+ monitorId: { type: mongoose.Types.ObjectId, ref: "Monitors" },
6
+ currentColor: { type: String, default: "16000" },
7
+ isActive: { type: Boolean, default: false },
8
+ configuration: {
9
+ hueUsername: { type: String },
10
+ clientId: { type: String, required: true },
11
+ clientSecret: { type: String, required: true },
12
+ lightId: { type: String, required: true },
13
+ accessTokenInfo: Object,
14
+ accessTokenCapturedAt: { type: Date },
15
+ refreshTokenInfo: Object,
16
+ refreshTokenCapturedAt: { type: Date },
17
+ hueCode: { type: String, required: true },
18
+ hueCodeHistory: [Object],
19
+ },
20
+ },
21
+ {
22
+ timestamps: true,
23
+ }
24
+ );
25
+
26
+ lightMonitorSchema.index({ monitorId: 1 });
27
+
28
+ const LightMonitors = mongoose.model("LightMonitor", lightMonitorSchema);
29
+
30
+ export { lightMonitorSchema, LightMonitors };