mongo-locks 3.1.1 → 3.2.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.
@@ -0,0 +1,48 @@
1
+ import { Collection, ObjectId } from "mongodb";
2
+ export declare class MongoLocksError extends Error {
3
+ constructor(message?: string);
4
+ }
5
+ interface LockModel {
6
+ _id: ObjectId;
7
+ action: unknown;
8
+ createdAt: Date;
9
+ refreshedAt: Date;
10
+ expiresAt: Date;
11
+ }
12
+ declare class Lock {
13
+ _id: ObjectId;
14
+ action: unknown;
15
+ collection: Collection<LockModel>;
16
+ constructor(_id: ObjectId, action: unknown, collection: Collection<LockModel>);
17
+ locked: boolean;
18
+ /**
19
+ * Instead of calling `this.free` directly you can use the `using` syntax
20
+ *
21
+ * @returns true if the lock was successfully released. False if the lock was not found
22
+ */
23
+ free(): Promise<boolean>;
24
+ /**
25
+ * Refreshes the lock's TTL
26
+ *
27
+ * Automatically called every 10 seconds if the lock is still active, no
28
+ * need to call this manually
29
+ *
30
+ * @returns true if the lock was successfully refreshed. False if the lock was not found
31
+ */
32
+ refresh(): Promise<boolean>;
33
+ [Symbol.dispose](): void;
34
+ [Symbol.asyncDispose](): Promise<boolean>;
35
+ }
36
+ export declare class LockManager {
37
+ collection: Collection<LockModel>;
38
+ private readonly ready;
39
+ MongoLocksError: typeof MongoLocksError;
40
+ constructor(collection: Collection);
41
+ /**
42
+ * Creates a DB lock based on the key provided
43
+ *
44
+ * @returns a function that when called will release the lock
45
+ */
46
+ lock(key: unknown): Promise<Lock | null>;
47
+ }
48
+ export type { LockModel, Lock };
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  Object.defineProperty(exports, "__esModule", { value: true });
12
3
  exports.LockManager = exports.MongoLocksError = void 0;
13
4
  const mongodb_1 = require("mongodb");
@@ -22,36 +13,37 @@ const makeKey = (key) => {
22
13
  return Array.isArray(key) ? { _key_array: key } : key;
23
14
  };
24
15
  class Lock {
16
+ _id;
17
+ action;
18
+ collection;
25
19
  constructor(_id, action, collection) {
26
20
  this._id = _id;
27
21
  this.action = action;
28
22
  this.collection = collection;
29
- this.locked = true;
30
23
  if (this.locked) {
31
- (() => __awaiter(this, void 0, void 0, function* () {
24
+ (async () => {
32
25
  while (this.locked) {
33
- yield new Promise((resolve) => setTimeout(resolve, 10000));
34
- yield this.refresh().catch(() => {
26
+ await new Promise((resolve) => setTimeout(resolve, 10_000));
27
+ await this.refresh().catch(() => {
35
28
  console.error("Failed to refresh lock", action);
36
29
  });
37
30
  }
38
- }))();
31
+ })();
39
32
  }
40
33
  }
34
+ locked = true;
41
35
  /**
42
36
  * Instead of calling `this.free` directly you can use the `using` syntax
43
37
  *
44
38
  * @returns true if the lock was successfully released. False if the lock was not found
45
39
  */
46
- free() {
47
- return __awaiter(this, void 0, void 0, function* () {
48
- if (!this.locked) {
49
- return false;
50
- }
51
- this.locked = false;
52
- const result = yield this.collection.deleteOne({ _id: this._id });
53
- return result.deletedCount === 1;
54
- });
40
+ async free() {
41
+ if (!this.locked) {
42
+ return false;
43
+ }
44
+ this.locked = false;
45
+ const result = await this.collection.deleteOne({ _id: this._id });
46
+ return result.deletedCount === 1;
55
47
  }
56
48
  /**
57
49
  * Refreshes the lock's TTL
@@ -61,58 +53,58 @@ class Lock {
61
53
  *
62
54
  * @returns true if the lock was successfully refreshed. False if the lock was not found
63
55
  */
64
- refresh() {
65
- return __awaiter(this, void 0, void 0, function* () {
66
- if (!this.locked) {
67
- return false;
68
- }
69
- const res = yield this.collection.updateOne({ _id: this._id }, { $set: { refreshedAt: new Date(), expiresAt: new Date(Date.now() + 60000) } });
70
- this.locked = res.matchedCount === 1;
71
- return this.locked;
72
- });
56
+ async refresh() {
57
+ if (!this.locked) {
58
+ return false;
59
+ }
60
+ const res = await this.collection.updateOne({ _id: this._id }, { $set: { refreshedAt: new Date(), expiresAt: new Date(Date.now() + 60_000) } });
61
+ this.locked = res.matchedCount === 1;
62
+ return this.locked;
73
63
  }
74
64
  [Symbol.dispose]() {
75
65
  this.free();
76
66
  }
77
- [Symbol.asyncDispose]() {
78
- return __awaiter(this, void 0, void 0, function* () {
79
- return this.free();
80
- });
67
+ async [Symbol.asyncDispose]() {
68
+ return this.free();
81
69
  }
82
70
  }
83
71
  class LockManager {
72
+ collection;
73
+ ready;
74
+ MongoLocksError = MongoLocksError;
84
75
  constructor(collection) {
85
- this.MongoLocksError = MongoLocksError;
86
76
  this.collection = collection;
87
- collection.createIndex({ action: 1 }, { unique: true });
88
- collection.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });
77
+ this.ready = collection.createIndexes([
78
+ { key: { action: 1 }, unique: true },
79
+ { key: { expiresAt: 1 }, expireAfterSeconds: 0 },
80
+ ]);
89
81
  }
90
82
  /**
91
83
  * Creates a DB lock based on the key provided
92
84
  *
93
85
  * @returns a function that when called will release the lock
94
86
  */
95
- lock(key) {
96
- return __awaiter(this, void 0, void 0, function* () {
97
- const lockId = makeKey(key);
98
- const id = new mongodb_1.ObjectId();
99
- try {
100
- yield this.collection.insertOne({
101
- _id: id,
102
- action: lockId,
103
- createdAt: new Date(),
104
- refreshedAt: new Date(),
105
- expiresAt: new Date(Date.now() + 60000),
106
- });
107
- return new Lock(id, lockId, this.collection);
108
- }
109
- catch (err) {
110
- if (err instanceof Error && "code" in err && err.code === 11000) {
111
- return null;
112
- }
113
- throw err;
87
+ async lock(key) {
88
+ await this.ready;
89
+ const lockId = makeKey(key);
90
+ const id = new mongodb_1.ObjectId();
91
+ try {
92
+ await this.collection.insertOne({
93
+ _id: id,
94
+ action: lockId,
95
+ createdAt: new Date(),
96
+ refreshedAt: new Date(),
97
+ expiresAt: new Date(Date.now() + 60_000),
98
+ });
99
+ return new Lock(id, lockId, this.collection);
100
+ }
101
+ catch (err) {
102
+ if (err instanceof Error && "code" in err && err.code === 11000) {
103
+ return null;
114
104
  }
115
- });
105
+ throw err;
106
+ }
116
107
  }
117
108
  }
118
109
  exports.LockManager = LockManager;
110
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import { Collection, ObjectId } from "mongodb";
2
+ export declare class MongoLocksError extends Error {
3
+ constructor(message?: string);
4
+ }
5
+ interface LockModel {
6
+ _id: ObjectId;
7
+ action: unknown;
8
+ createdAt: Date;
9
+ refreshedAt: Date;
10
+ expiresAt: Date;
11
+ }
12
+ declare class Lock {
13
+ _id: ObjectId;
14
+ action: unknown;
15
+ collection: Collection<LockModel>;
16
+ constructor(_id: ObjectId, action: unknown, collection: Collection<LockModel>);
17
+ locked: boolean;
18
+ /**
19
+ * Instead of calling `this.free` directly you can use the `using` syntax
20
+ *
21
+ * @returns true if the lock was successfully released. False if the lock was not found
22
+ */
23
+ free(): Promise<boolean>;
24
+ /**
25
+ * Refreshes the lock's TTL
26
+ *
27
+ * Automatically called every 10 seconds if the lock is still active, no
28
+ * need to call this manually
29
+ *
30
+ * @returns true if the lock was successfully refreshed. False if the lock was not found
31
+ */
32
+ refresh(): Promise<boolean>;
33
+ [Symbol.dispose](): void;
34
+ [Symbol.asyncDispose](): Promise<boolean>;
35
+ }
36
+ export declare class LockManager {
37
+ collection: Collection<LockModel>;
38
+ private readonly ready;
39
+ MongoLocksError: typeof MongoLocksError;
40
+ constructor(collection: Collection);
41
+ /**
42
+ * Creates a DB lock based on the key provided
43
+ *
44
+ * @returns a function that when called will release the lock
45
+ */
46
+ lock(key: unknown): Promise<Lock | null>;
47
+ }
48
+ export type { LockModel, Lock };
package/dist/esm/index.js CHANGED
@@ -1,12 +1,3 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { ObjectId } from "mongodb";
11
2
  export class MongoLocksError extends Error {
12
3
  constructor(message) {
@@ -18,36 +9,37 @@ const makeKey = (key) => {
18
9
  return Array.isArray(key) ? { _key_array: key } : key;
19
10
  };
20
11
  class Lock {
12
+ _id;
13
+ action;
14
+ collection;
21
15
  constructor(_id, action, collection) {
22
16
  this._id = _id;
23
17
  this.action = action;
24
18
  this.collection = collection;
25
- this.locked = true;
26
19
  if (this.locked) {
27
- (() => __awaiter(this, void 0, void 0, function* () {
20
+ (async () => {
28
21
  while (this.locked) {
29
- yield new Promise((resolve) => setTimeout(resolve, 10000));
30
- yield this.refresh().catch(() => {
22
+ await new Promise((resolve) => setTimeout(resolve, 10_000));
23
+ await this.refresh().catch(() => {
31
24
  console.error("Failed to refresh lock", action);
32
25
  });
33
26
  }
34
- }))();
27
+ })();
35
28
  }
36
29
  }
30
+ locked = true;
37
31
  /**
38
32
  * Instead of calling `this.free` directly you can use the `using` syntax
39
33
  *
40
34
  * @returns true if the lock was successfully released. False if the lock was not found
41
35
  */
42
- free() {
43
- return __awaiter(this, void 0, void 0, function* () {
44
- if (!this.locked) {
45
- return false;
46
- }
47
- this.locked = false;
48
- const result = yield this.collection.deleteOne({ _id: this._id });
49
- return result.deletedCount === 1;
50
- });
36
+ async free() {
37
+ if (!this.locked) {
38
+ return false;
39
+ }
40
+ this.locked = false;
41
+ const result = await this.collection.deleteOne({ _id: this._id });
42
+ return result.deletedCount === 1;
51
43
  }
52
44
  /**
53
45
  * Refreshes the lock's TTL
@@ -57,57 +49,57 @@ class Lock {
57
49
  *
58
50
  * @returns true if the lock was successfully refreshed. False if the lock was not found
59
51
  */
60
- refresh() {
61
- return __awaiter(this, void 0, void 0, function* () {
62
- if (!this.locked) {
63
- return false;
64
- }
65
- const res = yield this.collection.updateOne({ _id: this._id }, { $set: { refreshedAt: new Date(), expiresAt: new Date(Date.now() + 60000) } });
66
- this.locked = res.matchedCount === 1;
67
- return this.locked;
68
- });
52
+ async refresh() {
53
+ if (!this.locked) {
54
+ return false;
55
+ }
56
+ const res = await this.collection.updateOne({ _id: this._id }, { $set: { refreshedAt: new Date(), expiresAt: new Date(Date.now() + 60_000) } });
57
+ this.locked = res.matchedCount === 1;
58
+ return this.locked;
69
59
  }
70
60
  [Symbol.dispose]() {
71
61
  this.free();
72
62
  }
73
- [Symbol.asyncDispose]() {
74
- return __awaiter(this, void 0, void 0, function* () {
75
- return this.free();
76
- });
63
+ async [Symbol.asyncDispose]() {
64
+ return this.free();
77
65
  }
78
66
  }
79
67
  export class LockManager {
68
+ collection;
69
+ ready;
70
+ MongoLocksError = MongoLocksError;
80
71
  constructor(collection) {
81
- this.MongoLocksError = MongoLocksError;
82
72
  this.collection = collection;
83
- collection.createIndex({ action: 1 }, { unique: true });
84
- collection.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });
73
+ this.ready = collection.createIndexes([
74
+ { key: { action: 1 }, unique: true },
75
+ { key: { expiresAt: 1 }, expireAfterSeconds: 0 },
76
+ ]);
85
77
  }
86
78
  /**
87
79
  * Creates a DB lock based on the key provided
88
80
  *
89
81
  * @returns a function that when called will release the lock
90
82
  */
91
- lock(key) {
92
- return __awaiter(this, void 0, void 0, function* () {
93
- const lockId = makeKey(key);
94
- const id = new ObjectId();
95
- try {
96
- yield this.collection.insertOne({
97
- _id: id,
98
- action: lockId,
99
- createdAt: new Date(),
100
- refreshedAt: new Date(),
101
- expiresAt: new Date(Date.now() + 60000),
102
- });
103
- return new Lock(id, lockId, this.collection);
104
- }
105
- catch (err) {
106
- if (err instanceof Error && "code" in err && err.code === 11000) {
107
- return null;
108
- }
109
- throw err;
83
+ async lock(key) {
84
+ await this.ready;
85
+ const lockId = makeKey(key);
86
+ const id = new ObjectId();
87
+ try {
88
+ await this.collection.insertOne({
89
+ _id: id,
90
+ action: lockId,
91
+ createdAt: new Date(),
92
+ refreshedAt: new Date(),
93
+ expiresAt: new Date(Date.now() + 60_000),
94
+ });
95
+ return new Lock(id, lockId, this.collection);
96
+ }
97
+ catch (err) {
98
+ if (err instanceof Error && "code" in err && err.code === 11000) {
99
+ return null;
110
100
  }
111
- });
101
+ throw err;
102
+ }
112
103
  }
113
104
  }
105
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongo-locks",
3
3
  "type": "module",
4
- "version": "3.1.1",
4
+ "version": "3.2.0",
5
5
  "description": "Simple and bountiful locks to avoid doing the same operation multiple times",
6
6
  "main": "./dist/commonjs/index.js",
7
7
  "scripts": {
@@ -32,7 +32,7 @@
32
32
  "@types/node": "^22.12.7",
33
33
  "mongodb": "^6.5.0",
34
34
  "tshy": "^3.1.0",
35
- "typescript": "^5.4.5"
35
+ "typescript": "^5.9.0"
36
36
  },
37
37
  "files": [
38
38
  "dist",
package/src/index.ts CHANGED
@@ -84,13 +84,16 @@ class Lock {
84
84
 
85
85
  export class LockManager {
86
86
  collection: Collection<LockModel>;
87
+ private readonly ready: Promise<string[]>;
87
88
  MongoLocksError = MongoLocksError;
88
89
 
89
90
  constructor(collection: Collection) {
90
91
  this.collection = collection as unknown as Collection<LockModel>;
91
92
 
92
- collection.createIndex({ action: 1 }, { unique: true });
93
- collection.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });
93
+ this.ready = collection.createIndexes([
94
+ { key: { action: 1 }, unique: true },
95
+ { key: { expiresAt: 1 }, expireAfterSeconds: 0 },
96
+ ]);
94
97
  }
95
98
 
96
99
  /**
@@ -99,6 +102,8 @@ export class LockManager {
99
102
  * @returns a function that when called will release the lock
100
103
  */
101
104
  async lock(key: unknown): Promise<Lock | null> {
105
+ await this.ready;
106
+
102
107
  const lockId = makeKey(key);
103
108
  const id = new ObjectId();
104
109
 
package/tsconfig.json CHANGED
@@ -2,20 +2,13 @@
2
2
  "compilerOptions": {
3
3
  "strict": true,
4
4
  /* Basic Options */
5
- "target": "es2015",
6
- "module": "commonjs",
7
- // "declaration": true, /* Generates corresponding '.d.ts' file. */
8
- "sourceMap": false, /* Generates corresponding '.map' file. */
9
- // "outFile": "./", /* Concatenate and emit output to single file. */
10
- "outDir": "./dist", /* Redirect output structure to the directory. */
5
+ "target": "es2022",
6
+ "module": "NodeNext",
7
+ "moduleResolution": "NodeNext",
8
+ "declaration": true /* Generates corresponding '.d.ts' file. */,
9
+ "sourceMap": true /* Generates corresponding '.map' file. */,
10
+ "outDir": "./dist" /* Redirect output structure to the directory. */
11
11
  },
12
- "include": [
13
- "src/**/*.ts",
14
- "index.ts"
15
- ],
16
- "exclude": [
17
- "node_modules",
18
- "dist",
19
- "**/*.spec.ts"
20
- ]
21
- }
12
+ "include": ["src/**/*.ts", "index.ts"],
13
+ "exclude": ["node_modules", "dist", "**/*.spec.ts"]
14
+ }