@sedni/cloud_common 1.1.0 → 2.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.
package/package.json CHANGED
@@ -1,15 +1,25 @@
1
1
  {
2
2
  "name": "@sedni/cloud_common",
3
- "version": "1.1.0",
3
+ "version": "2.0.0",
4
4
  "description": "Common package for all types, resources and tools of Diamar Cloud",
5
- "main": "index.js",
5
+ "type": "module",
6
+ "main": "./dist/node-entry.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
6
9
  "scripts": {
10
+ "build": "tsup app/index.ts app/node-entry.cjs --format esm,cjs --dts --out-dir dist",
7
11
  "test": "cross-env NODE_ENV=internal_test mocha --recursive --exit app/test/*",
8
12
  "coverage": "nyc --include 'app/**/*controller.js' mocha",
9
13
  "lint": "eslint app/*",
10
14
  "lint:fix": "eslint --fix app/*",
11
15
  "playground": "node playground.js"
12
16
  },
17
+ "exports": {
18
+ ".": {
19
+ "import": "./dist/index.js",
20
+ "require": "./dist/node-entry.cjs"
21
+ }
22
+ },
13
23
  "author": "Jose Luis Silvestre García",
14
24
  "license": "ISC",
15
25
  "dependencies": {
@@ -20,6 +30,7 @@
20
30
  },
21
31
  "devDependencies": {
22
32
  "@eslint/js": "^9.32.0",
33
+ "@types/node": "^24.10.1",
23
34
  "chai": "^5.2.1",
24
35
  "eslint": "^9.32.0",
25
36
  "eslint-plugin-n": "^17.21.0",
@@ -28,6 +39,8 @@
28
39
  "nyc": "^17.1.0",
29
40
  "proxyquire": "^2.1.3",
30
41
  "sinon": "^21.0.0",
31
- "supertest": "^7.1.4"
42
+ "supertest": "^7.1.4",
43
+ "tsup": "^8.5.0",
44
+ "typescript": "^5.9.3"
32
45
  }
33
46
  }
package/tsconfig.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "moduleResolution": "node",
6
+ "allowJs": true,
7
+ "checkJs": false,
8
+ "declaration": true,
9
+ "outDir": "./dist",
10
+ "rootDir": "app",
11
+ "strict": true,
12
+ "resolveJsonModule": true,
13
+ "esModuleInterop": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "skipLibCheck": true
16
+ },
17
+ "include": [
18
+ "app/**/*"
19
+ ]
20
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "module": "CommonJS",
5
+ "outDir": "./dist",
6
+ "declaration": false
7
+ },
8
+ "include": [
9
+ "app/node-entry.ts",
10
+ "app/models/**/*.js"
11
+ ]
12
+ }
@@ -1,73 +0,0 @@
1
- const mongoose = require("mongoose");
2
- const mongooseAutopopulate = require("mongoose-autopopulate");
3
- const mongoosePaginate = require("mongoose-paginate-v2");
4
- const mongooseAggregatePaginate = require("mongoose-aggregate-paginate-v2");
5
-
6
- const channelSchema = new mongoose.Schema({
7
- channel_tag: {
8
- type: String,
9
- required: true,
10
- },
11
- channel_description: {
12
- type: String,
13
- required: true,
14
- },
15
- channel_unit_id: {
16
- type: mongoose.Schema.Types.ObjectId,
17
- ref: "Unit",
18
- required: true,
19
- autopopulate: true,
20
- },
21
- channel_parsed : {
22
- type: Object,
23
- required: true,
24
- },
25
- channel_last_bucket_sync: {
26
- type: Date,
27
- required: false,
28
- },
29
- }, {
30
- timestamps: {
31
- createdAt: true,
32
- updatedAt: true
33
- },
34
- collection: "channels",
35
- toJSON: {
36
- transform: function (doc, ret)
37
- {
38
- ret.id = ret._id;
39
- ret.channel_unit = ret.channel_unit_id;
40
- ret.channel_unit_id = ret.channel_unit_id.unit_id;
41
- delete ret._id;
42
- delete ret.__v;
43
- },
44
- },
45
- });
46
-
47
- /**
48
- * ///////////////////////////////////////////////
49
- * ///////////// INDEXES /////////////////
50
- * ///////////////////////////////////////////////
51
- */
52
-
53
- /**
54
- * Index used primarily for filtering by channel_tag
55
- */
56
- channelSchema.index({ "channel_tag" : 1 }, { unique: true });
57
-
58
- /**
59
- * Index used primarily for filtering by channel_description
60
- */
61
- channelSchema.index({ "channel_description" : 1 });
62
-
63
-
64
- /**
65
- * ///////////////////////////////////////////////
66
- * ///////////// PLUGINS /////////////////
67
- * ///////////////////////////////////////////////
68
- */
69
- channelSchema.plugin(mongoosePaginate);
70
- channelSchema.plugin(mongooseAggregatePaginate);
71
- channelSchema.plugin(mongooseAutopopulate);
72
-
73
- module.exports = channelSchema;
@@ -1,321 +0,0 @@
1
- const mongoose = require("mongoose");
2
- const mongooseAutopopulate = require("mongoose-autopopulate");
3
- const mongoosePaginate = require("mongoose-paginate-v2");
4
- const mongooseAggregatePaginate = require("mongoose-aggregate-paginate-v2");
5
-
6
- const dataPointSchema = new mongoose.Schema({
7
- timestamp: {
8
- type: Number,
9
- required: true,
10
- },
11
- value: {
12
- type: Number,
13
- required: true,
14
- }
15
- }, {
16
- _id: false,
17
- });
18
-
19
- const channeldataBucketSchema = new mongoose.Schema({
20
- start_date: {
21
- type: Date,
22
- required: true,
23
- default: Date.now,
24
- },
25
- end_date: {
26
- type: Date,
27
- required: true,
28
- default: function()
29
- {
30
- return new Date(Date.now() + 1000 * 60 * 60); // 1 hour from now
31
- }
32
- },
33
- data : {
34
- type: [dataPointSchema],
35
- required: true,
36
- default: [],
37
- },
38
- size : {
39
- type: Number,
40
- required: true,
41
- default: 0,
42
- },
43
- synced : {
44
- type: Number,
45
- required: true,
46
- default: 0,
47
- },
48
- sum : {
49
- type: Number,
50
- required: true,
51
- default: 0,
52
- },
53
- }, {
54
- toJSON: {
55
- transform: function (doc, ret)
56
- {
57
- ret.id = ret._id;
58
- delete ret._id;
59
- delete ret.__v;
60
- ret.start_date = ret.start_date.getTime();
61
- ret.end_date = ret.end_date.getTime();
62
- ret.avg = ret.sum / ret.size;
63
- },
64
- },
65
- versionKey: false,
66
- });
67
-
68
- /**
69
- * ///////////////////////////////////////////////
70
- * ///////////// INDEXES /////////////////
71
- * ///////////////////////////////////////////////
72
- */
73
-
74
- /**
75
- * Index the start_date and end_date fields for faster queries.
76
- * The compound index will be used to query the buckets by date range.
77
- */
78
- channeldataBucketSchema.index({ start_date: 1, end_date: 1 });
79
-
80
- /**
81
- * Index used to delete old buckets automatically.
82
- * This function will need to be called to create the TTL index.
83
- * The index will expire documents after the specified time in seconds.
84
- * The default is set to one year, but it can be changed by passing the expirationTimeInSeconds parameter.
85
- */
86
- const oneYear = 60 * 60 * 24 * 365; // One year in seconds
87
- channeldataBucketSchema.addTTLIndex = function(ttlField, expirationTimeInSeconds = oneYear)
88
- {
89
- this.index({ [ttlField]: 1 }, { expireAfterSeconds: expirationTimeInSeconds });
90
- }
91
-
92
- /**
93
- * ///////////////////////////////////////////////
94
- * ///////////// PLUGINS /////////////////
95
- * ///////////////////////////////////////////////
96
- */
97
- channeldataBucketSchema.plugin(mongoosePaginate);
98
- channeldataBucketSchema.plugin(mongooseAggregatePaginate);
99
- channeldataBucketSchema.plugin(mongooseAutopopulate);
100
-
101
-
102
- /**
103
- * ///////////////////////////////////////////////
104
- * //////////// FUNCTIONS ////////////////
105
- * ///////////////////////////////////////////////
106
- */
107
- /**
108
- * Insert a data point into a specific bucket.
109
- *
110
- * The data point will be inserted into the bucket and the size and sum will be updated.
111
- * @param {Number} timestamp The timestamp of the data point
112
- * @param {Number} value The value of the data point
113
- */
114
- channeldataBucketSchema.methods.insertDataPoint = async function(timestamp, value)
115
- {
116
- this.data.push({ timestamp: timestamp, value: value });
117
- this.size++;
118
- this.sum += value;
119
- await this.save();
120
- };
121
-
122
- /**
123
- * Remove data points outside the specified date range within the bucket.
124
- *
125
- * IT WILL NOT SAVE THE BUCKET, YOU NEED TO CALL save() AFTER THIS FUNCTION TO SAVE THE BUCKET
126
- * @param {Number | Date} start_date The start date of the date range
127
- * @param {Number | Date} end_date The end date of the date range
128
- */
129
- channeldataBucketSchema.methods.removeDataPointsOutsideDateRange = function(start_date, end_date)
130
- {
131
- start_date = start_date instanceof Date ? start_date.getTime() : start_date;
132
- end_date = end_date instanceof Date ? end_date.getTime() : end_date;
133
-
134
- this.data = this.data.filter(data_point => data_point.timestamp >= start_date && data_point.timestamp < end_date);
135
- this.size = this.data.length;
136
- this.sum = this.data.reduce((sum, data_point) => sum + data_point.value, 0);
137
- };
138
-
139
- /**
140
- * Check if the bucket is closed, meaning that it is no longer accepting data points.
141
- * @param {Number} timestamp The timestamp to check if the bucket is closed
142
- * @returns {Boolean} True if the bucket is closed, false otherwise
143
- */
144
- channeldataBucketSchema.methods.isBucketClosed = function(timestamp = Date.now())
145
- {
146
- return timestamp >= this.end_date.getTime();
147
- };
148
-
149
- /**
150
- * Insert a data point into the corresponding bucket.
151
- *
152
- * If no bucket exists for the timestamp, it will be created.
153
- * If a bucket exists for the timestamp, the data point will be inserted into the bucket and the size and sum will be updated.
154
- * @param {Number} timestamp The timestamp of the data point
155
- * @param {Number} value The value of the data point
156
- * @returns {Object} The bucket that the data point was inserted into
157
- */
158
- channeldataBucketSchema.statics.insertDataPoint = async function(timestamp, value)
159
- {
160
- // Truncate the timestamp to the nearest hour
161
- const date = new Date(timestamp);
162
- date.setMinutes(0);
163
- date.setSeconds(0);
164
- date.setMilliseconds(0);
165
-
166
- // Upsert the data point
167
- const bucket = await this.findOneAndUpdate(
168
- {
169
- start_date: date
170
- },
171
- {
172
- $push:
173
- {
174
- data:
175
- {
176
- timestamp: timestamp,
177
- value: value
178
- }
179
- },
180
-
181
- $inc:
182
- {
183
- size: 1,
184
- sum: value
185
- },
186
-
187
- $set:
188
- {
189
- end_date: new Date(date.getTime() + 1000 * 60 * 60),
190
- }
191
- },
192
- {
193
- upsert: true,
194
- new: true
195
- }
196
- );
197
-
198
- return bucket;
199
- };
200
-
201
- /**
202
- * Get the last time the data was synced
203
- * @param {Object} options The options to get the last time the data was synced
204
- * @param {String} options.channel_tag The channel tag to get the data from
205
- * @param {Object} options.db The database to get the channel document from
206
- * @returns {Number} The last time the data was synced
207
- */
208
- channeldataBucketSchema.statics.lastTimeSynced = async function(options)
209
- {
210
- let last_sync = 0;
211
- if(options?.channel_tag && options?.db)
212
- {
213
- // Get the last time the data was synced
214
- const channel = await options.db.collection("channels").findOne({
215
- channel_tag : options.channel_tag
216
- });
217
-
218
- last_sync = channel.channel_last_bucket_sync.getTime();
219
- }
220
- return last_sync;
221
- };
222
-
223
- /**
224
- * Get the data that has not been uploaded to the cloud yet
225
- * @param {Object} options The options to get the data
226
- * @param {Date | Number} options.last_sync The last time the data was synced, if not provided it will be fetched from the channel document
227
- * @param {String} options.channel_tag The channel tag to get the data from, only used if last_sync is not provided
228
- * @param {Object} options.db The database to get the channel document from, only used if last_sync is not provided
229
- * @returns {Array} The data that has not been uploaded to the cloud yet
230
- */
231
- channeldataBucketSchema.statics.getNotUploadedData = async function(options)
232
- {
233
- // Get the last time the data was synced
234
- const last_sync = options?.last_sync ?? await this.lastTimeSynced(options);
235
-
236
- // Get all the buckets that synced is lt size and end_date is gt last_sync
237
- const buckets = await this.find({
238
- end_date: {
239
- $gt: new Date(last_sync)
240
- }
241
- });
242
-
243
- return buckets;
244
- };
245
-
246
- /**
247
- * Get the data in the specified date range
248
- * @param {Date | Number} start_date The start date of the date range
249
- * @param {Date | Number} end_date The end date of the date range
250
- * @param {Boolean} plain If true, the data will be returned as an array of data points, otherwise it will be returned as an array of buckets
251
- * @returns {Array} The data in the specified date range. It will be an array of data points if plain is true, otherwise it will be an array of buckets
252
- */
253
- channeldataBucketSchema.statics.getData = async function(start_date, end_date, plain = false)
254
- {
255
- // Truncate the timestamp to the nearest hour
256
- const date = new Date(start_date);
257
- date.setMinutes(0);
258
- date.setSeconds(0);
259
- date.setMilliseconds(0);
260
-
261
- // Get the data in the specified date range
262
- const data = await this.find({
263
- start_date: {
264
- $gte: date,
265
- $lt: new Date(end_date)
266
- }
267
- });
268
-
269
- if(!data || data.length === 0)
270
- {
271
- return [];
272
- }
273
-
274
- // Remove the data inside the bucket that is not in the specified date range
275
- data[0].removeDataPointsOutsideDateRange(start_date, end_date);
276
-
277
- if(data.length > 1)
278
- {
279
- data[1].removeDataPointsOutsideDateRange(start_date, end_date);
280
- }
281
-
282
- return plain ? data.flatMap(bucket => {
283
- return bucket.data.map(data_point => {
284
- return {
285
- timestamp: data_point.timestamp,
286
- value: data_point.value
287
- };
288
- });
289
- }) : data;
290
- };
291
-
292
-
293
- channeldataBucketSchema.statics.upsertBucket = async function(bucket)
294
- {
295
- const date = new Date(bucket.start_date);
296
- date.setMinutes(0);
297
- date.setSeconds(0);
298
- date.setMilliseconds(0);
299
-
300
- const result = await this.updateOne(
301
- {
302
- start_date: date
303
- },
304
- {
305
- $set:
306
- {
307
- data: bucket.data,
308
- size: bucket.size,
309
- sum: bucket.sum,
310
- end_date: new Date(date.getTime() + 1000 * 60 * 60),
311
- }
312
- },
313
- {
314
- upsert: true
315
- }
316
- );
317
-
318
- return result;
319
- };
320
-
321
- module.exports = channeldataBucketSchema;
@@ -1,90 +0,0 @@
1
- const mongoose = require("mongoose");
2
- const mongooseAutopopulate = require("mongoose-autopopulate");
3
- const mongoosePaginate = require("mongoose-paginate-v2");
4
- const mongooseAggregatePaginate = require("mongoose-aggregate-paginate-v2");
5
- const { EventCategories } = require("../types/event.types");
6
-
7
- const eventSchema = new mongoose.Schema({
8
- event_message: {
9
- type: String,
10
- required: true
11
- },
12
- event_source: {
13
- type: String,
14
- required: true
15
- },
16
- event_user: {
17
- type: String,
18
- required: false
19
- },
20
- event_category: {
21
- type: String,
22
- required: true,
23
- enum: Object.values(EventCategories)
24
- },
25
- event_type: {
26
- type: String,
27
- required: true
28
- },
29
- event_timestamp: {
30
- type: Date,
31
- default: Date.now,
32
- },
33
- event_data: {
34
- type: Object
35
- }
36
- }, {
37
- timestamps: {
38
- createdAt: true,
39
- updatedAt: false
40
- },
41
- versionKey: false,
42
- toJSON: {
43
- transform: function (doc, ret)
44
- {
45
- ret.id = ret._id;
46
- delete ret._id;
47
- delete ret.createdAt;
48
- ret.event_timestamp = ret.event_timestamp.getTime();
49
- }
50
- }
51
- });
52
-
53
- /**
54
- * ///////////////////////////////////////////////
55
- * ///////////// INDEXES /////////////////
56
- * ///////////////////////////////////////////////
57
- */
58
-
59
- /**
60
- * Index used primarily for filtering by event_type
61
- */
62
- eventSchema.index({ "event_type" : 1 });
63
-
64
- /**
65
- * Index used primarily for filtering by event_category
66
- */
67
- eventSchema.index({ "event_category" : 1 });
68
-
69
- /**
70
- * Index used to delete old events automatically.
71
- * This function will need to be called to create the TTL index.
72
- * The index will expire documents after the specified time in seconds.
73
- * The default is set to one year, but it can be changed by passing the expirationTimeInSeconds parameter.
74
- */
75
- const oneYear = 60 * 60 * 24 * 365; // One year in seconds
76
- eventSchema.addTTLIndex = function(ttlField, expirationTimeInSeconds = oneYear)
77
- {
78
- this.index({ [ttlField]: 1 }, { expireAfterSeconds: expirationTimeInSeconds });
79
- }
80
-
81
- /**
82
- * ///////////////////////////////////////////////
83
- * ///////////// PLUGINS /////////////////
84
- * ///////////////////////////////////////////////
85
- */
86
- eventSchema.plugin(mongoosePaginate);
87
- eventSchema.plugin(mongooseAggregatePaginate);
88
- eventSchema.plugin(mongooseAutopopulate);
89
-
90
- module.exports = eventSchema;
@@ -1,106 +0,0 @@
1
- const mongoose = require("mongoose");
2
- const mongooseAutopopulate = require("mongoose-autopopulate");
3
- const mongoosePaginate = require("mongoose-paginate-v2");
4
- const mongooseAggregatePaginate = require("mongoose-aggregate-paginate-v2");
5
- const { AlarmTypes, AlarmPriorities, CloudAlarmStates, DiamarAlarmStates } = require("../types/alarm.types");
6
-
7
- const historySchema = new mongoose.Schema({
8
- channel_tag: {
9
- type: String,
10
- required: true,
11
- },
12
- alarm_timestamp: {
13
- type: Date,
14
- required: true,
15
- default: Date.now,
16
- },
17
- alarm_priority: {
18
- type: String,
19
- required: true,
20
- enum: Object.values(AlarmPriorities),
21
- },
22
- alarm_original_state: {
23
- type: String,
24
- required: true,
25
- enum: Object.values(DiamarAlarmStates),
26
- },
27
- alarm_state: {
28
- type: String,
29
- required: true,
30
- enum: Object.values(CloudAlarmStates),
31
- },
32
- alarm_type: {
33
- type: String,
34
- required: true,
35
- enum: Object.values(AlarmTypes),
36
- },
37
- alarm_value: {
38
- type: Number,
39
- required: false,
40
- },
41
- alarm_message: {
42
- type: String,
43
- required: false,
44
- },
45
- alarm_data: {
46
- type: Object,
47
- required: false,
48
- },
49
- }, {
50
- timestamps: {
51
- createdAt: false,
52
- updatedAt: false
53
- },
54
- versionKey: false,
55
- collection: "history",
56
- toJSON: {
57
- transform: function (doc, ret)
58
- {
59
- ret.id = ret._id;
60
- delete ret._id;
61
- delete ret.__v;
62
- ret.alarm_timestamp = new Date(ret.alarm_timestamp).getTime();
63
- ret.alarm = {
64
- alarm_priority: ret.alarm_priority,
65
- alarm_state: ret.alarm_original_state ?? "Inactive",
66
- alarm_type: ret.alarm_type,
67
- alarm_value: ret.alarm_value === null ? "inf" : `${ret.alarm_value}`,
68
- alarm_timestamp: new Date(ret.alarm_timestamp).getTime()
69
- };
70
- },
71
- },
72
- });
73
-
74
- /**
75
- * ///////////////////////////////////////////////
76
- * ///////////// INDEXES /////////////////
77
- * ///////////////////////////////////////////////
78
- */
79
-
80
- /**
81
- * Index used primarily for filtering by channel_tag
82
- */
83
- historySchema.index({ "channel_tag" : 1 });
84
-
85
- /**
86
- * Index used to delete old alarms automatically.
87
- * This function will need to be called to create the TTL index.
88
- * The index will expire documents after the specified time in seconds.
89
- * The default is set to one year, but it can be changed by passing the expirationTimeInSeconds parameter.
90
- */
91
- const oneYear = 60 * 60 * 24 * 365; // One year in seconds
92
- historySchema.addTTLIndex = function(ttlField, expirationTimeInSeconds = oneYear)
93
- {
94
- this.index({ [ttlField]: 1 }, { expireAfterSeconds: expirationTimeInSeconds });
95
- }
96
-
97
- /**
98
- * ///////////////////////////////////////////////
99
- * ///////////// PLUGINS /////////////////
100
- * ///////////////////////////////////////////////
101
- */
102
- historySchema.plugin(mongoosePaginate);
103
- historySchema.plugin(mongooseAggregatePaginate);
104
- historySchema.plugin(mongooseAutopopulate);
105
-
106
- module.exports = historySchema;