@adaptivestone/framework 5.0.0-beta.6 → 5.0.0-beta.8

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/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ### 5.0.0-beta.8
2
+
3
+ [UPDATE] update deps
4
+ [NEW] Lock model for workingwir locks via mongoDB
5
+
6
+ ### 5.0.0-beta.7
7
+
8
+ [UPDATE] update deps
9
+ [UPDATE] change vitest shutdown behavior as mongo driver v6.13 change befaviur that affect us (MongoClient.close now closes any outstanding cursors)
10
+
1
11
  ### 5.0.0-beta.5
2
12
 
3
13
  [BREAKING] remove minimist CLI parsing and replace it by commandArguments parser
package/jsconfig.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "module": "NodeNext",
4
- "target": "ES2022",
4
+ "target": "ES2024",
5
5
  "moduleResolution": "nodenext",
6
6
  "checkJs": true
7
7
  },
package/models/Lock.js ADDED
@@ -0,0 +1,107 @@
1
+ import AbstractModel from '../modules/AbstractModel.js';
2
+
3
+ class Lock extends AbstractModel {
4
+ initHooks() {
5
+ this.mongooseSchema.index({ expiredAt: 1 }, { expireAfterSeconds: 0 });
6
+ }
7
+
8
+ // eslint-disable-next-line class-methods-use-this
9
+ get modelSchema() {
10
+ return {
11
+ _id: { type: String, required: true },
12
+ expiredAt: {
13
+ type: Date,
14
+ },
15
+ };
16
+ }
17
+
18
+ /**
19
+ * acquire lock based on lock name
20
+ * @param {string} name
21
+ * @param {number} [ttlSeconds=30]
22
+ * @returns {Promise<boolean>}
23
+ */
24
+ static async acquireLock(name, ttlSeconds = 30) {
25
+ try {
26
+ await this.create({
27
+ _id: name,
28
+ expiredAt: new Date(Date.now() + ttlSeconds * 1000),
29
+ });
30
+ } catch (error) {
31
+ if (error.code !== 11000) {
32
+ // not a duplicate leys
33
+ throw error;
34
+ }
35
+ return false;
36
+ }
37
+ return true;
38
+ }
39
+
40
+ /**
41
+ * release lock based on lock name
42
+ * @param {string} name
43
+ * @returns {Promise<boolean>}
44
+ */
45
+ static async releaseLock(name) {
46
+ const res = await this.deleteOne({ _id: name });
47
+ if (res.acknowledged && res.deletedCount) {
48
+ return true;
49
+ }
50
+ return false;
51
+ }
52
+
53
+ /**
54
+ * wait lock based on lock name
55
+ * @param {string} name
56
+ * @returns {Promise}
57
+ */
58
+ static async waitForUnlock(name) {
59
+ const res = await this.findOne({ _id: name });
60
+ if (!res) {
61
+ return Promise.resolve();
62
+ }
63
+
64
+ return new Promise((resolve) => {
65
+ const stream = this.watch([
66
+ { $match: { operationType: 'delete', 'documentKey._id': name } },
67
+ ]);
68
+ stream.on('change', () => {
69
+ stream.close();
70
+ resolve();
71
+ });
72
+ });
73
+ }
74
+
75
+ /**
76
+ * get lock remaining time based on lock name
77
+ * @param {string} name
78
+ * @returns {Promise<{ttl: number}>}
79
+ */
80
+ static async getLockData(name) {
81
+ const res = await this.findOne({ _id: name });
82
+ if (!res) {
83
+ return { ttl: 0 };
84
+ }
85
+ return { ttl: res.expiredAt.getTime() - Date.now() };
86
+ }
87
+
88
+ /**
89
+ * get lock remaining time based on lock name
90
+ * @param {string[]} names
91
+ * @returns {Promise<{name: string, ttl: number}[]>}
92
+ */
93
+ static async getLocksData(names) {
94
+ const res = await this.find({ _id: { $in: names } });
95
+ const lockMap = new Map(res.map((lock) => [lock._id, lock]));
96
+
97
+ return names.map((name) => {
98
+ const lock = lockMap.get(name);
99
+ return {
100
+ name,
101
+ ttl: lock ? lock.expiredAt.getTime() - Date.now() : 0,
102
+ };
103
+ });
104
+ }
105
+ }
106
+
107
+ export default Lock;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaptivestone/framework",
3
- "version": "5.0.0-beta.6",
3
+ "version": "5.0.0-beta.8",
4
4
  "description": "Adaptive stone node js framework",
5
5
  "main": "index.js",
6
6
  "type": "module",
package/server.d.ts CHANGED
@@ -46,7 +46,7 @@ declare class Server {
46
46
  /**
47
47
  * Start server (http + init all http ralated functions)
48
48
  */
49
- startServer(callbackBefore404?: Promise<null>): Promise<null>;
49
+ startServer(callbackBefore404?: () => Promise<null>): Promise<null>;
50
50
 
51
51
  /**
52
52
  * Do an initialization (config reading, etc)
@@ -102,6 +102,11 @@ afterAll(async () => {
102
102
  if (typeof global.testSetup.afterAll === 'function') {
103
103
  await global.testSetup.afterAll();
104
104
  }
105
- await mongoose.connection.db.dropDatabase(); // clean database after test
105
+ try {
106
+ await mongoose.connection.db.dropDatabase(); // clean database after test
107
+ } catch {
108
+ // that ok. No mongoose connection
109
+ }
110
+
106
111
  await mongoose.disconnect();
107
112
  });