mongo-locks 2.0.1 → 3.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/README.md +34 -114
- package/dist/index.js +90 -29
- package/index.ts +105 -33
- package/package.json +13 -12
- package/dist/src/schema.js +0 -23
- package/src/schema.ts +0 -23
package/README.md
CHANGED
|
@@ -1,140 +1,60 @@
|
|
|
1
1
|
# mongo-locks
|
|
2
|
+
|
|
2
3
|
Simple and bountiful locks to avoid doing the same operation multiple times
|
|
3
4
|
|
|
4
5
|
The purpose of this package is simply to avoid doing the same thing twice at the same time
|
|
5
6
|
and make your system a bit more user-proof.
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
```ts
|
|
9
|
+
import { LockManager } from "mongo-locks";
|
|
10
|
+
import { MongoClient } from "mongodb";
|
|
11
|
+
|
|
12
|
+
const client = new MongoClient("mongodb://localhost:27017");
|
|
13
|
+
const lockManager = new LockManager(client.db().collection("mongo-locks"));
|
|
8
14
|
|
|
9
|
-
```js
|
|
10
15
|
async function doStuff() {
|
|
11
|
-
|
|
16
|
+
await using lock = lockManager.lock("unique string key");
|
|
12
17
|
|
|
13
|
-
|
|
18
|
+
if (!lock.locked) {
|
|
19
|
+
console.log("Lock already taken");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
14
22
|
|
|
15
|
-
|
|
16
|
-
//...
|
|
17
|
-
freeLock = await locks.lock("unique string key");
|
|
23
|
+
// do stuff
|
|
18
24
|
|
|
19
|
-
|
|
20
|
-
} catch(err) {
|
|
21
|
-
//...
|
|
22
|
-
} finally {
|
|
23
|
-
freeLock(); /* Gets started on releasing lock, can be awaited */
|
|
24
|
-
}
|
|
25
|
+
//lock is automatically freed
|
|
25
26
|
}
|
|
26
27
|
```
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
race conditions and doing the same action several times in a short span.
|
|
30
|
-
|
|
31
|
-
For a more concrete example:
|
|
29
|
+
If the process crashes while a lock is active, MongoDB will automatically free it after one minute or two.
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
process likes this way:
|
|
31
|
+
If you don't want to use the `using` syntax, you can do it this way:
|
|
35
32
|
|
|
36
|
-
```
|
|
37
|
-
|
|
33
|
+
```ts
|
|
34
|
+
async function doStuff() {
|
|
35
|
+
const lock = await lockManager.lock("unique string key");
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return res.redirect(req.post.getLink());
|
|
37
|
+
if (!lock.locked) {
|
|
38
|
+
console.log("Lock already taken");
|
|
39
|
+
return;
|
|
43
40
|
}
|
|
44
41
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
]).then(
|
|
50
|
-
() => res.redirect(req.post.getLink()), //when all done
|
|
51
|
-
next //in case of error, next(err) is called
|
|
52
|
-
);
|
|
53
|
-
});
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
The problem with this is that if a user accesses the "like" url twice very fast, for whatever
|
|
57
|
-
reason, the server can add the like on one hand while the silent check is already passed successfully
|
|
58
|
-
on the other hand, and boom, the user liked the same post twice!
|
|
59
|
-
|
|
60
|
-
This package aims to solve that problem. The code would now look like:
|
|
61
|
-
|
|
62
|
-
```js
|
|
63
|
-
const mongoose = require('mongoose');
|
|
64
|
-
const locks = require('mongo-locks');
|
|
65
|
-
|
|
66
|
-
locks.init(mongoose.connection); //do just once across the whole app
|
|
67
|
-
|
|
68
|
-
router.all("/like", isUserLoggedIn, (req, res, next) => {
|
|
69
|
-
/* Silently ignore attempt to like an already liked post */
|
|
70
|
-
if (req.user.doesLike(req.post.id)) {
|
|
71
|
-
return res.redirect(req.post.getLink());
|
|
42
|
+
try {
|
|
43
|
+
// do stuff
|
|
44
|
+
} finally {
|
|
45
|
+
await lock.free(); // or await lock[Symbol.asyncDispose]();
|
|
72
46
|
}
|
|
73
|
-
|
|
74
|
-
var freeLock = () => {};
|
|
75
|
-
/* Add post reference to user, and increase likes for post */
|
|
76
|
-
locks.lock("like", req.user.id, req.post.id).then((free) => {
|
|
77
|
-
freeLock = free;
|
|
78
|
-
return Promise.all([
|
|
79
|
-
req.user.update({$push: {likedPosts: {ref: req.post.id, title: req.post.title}}}),
|
|
80
|
-
req.post.update({$inc: {likes: 1}})
|
|
81
|
-
]);
|
|
82
|
-
}).then(() => res.redirect(req.post.getLink()), next)
|
|
83
|
-
.then(freeLock, freeLock);
|
|
84
|
-
});
|
|
47
|
+
}
|
|
85
48
|
```
|
|
86
49
|
|
|
87
|
-
|
|
88
|
-
that collection. It relies on MongoDB's unique indexes to guarantee an error
|
|
89
|
-
is returned in case the same lock is used twice.
|
|
50
|
+
## Mongoose
|
|
90
51
|
|
|
52
|
+
Mongoose let's you access the underlying collection of a model, so you can use it like this:
|
|
91
53
|
|
|
92
|
-
|
|
54
|
+
```ts
|
|
55
|
+
import { LockManager } from "mongo-locks";
|
|
56
|
+
import mongoose from "mongoose";
|
|
93
57
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
### .init(connection: mongoose.connection[, options])
|
|
97
|
-
|
|
98
|
-
Initialize the connection to the mongo database, needed before any calls to the other functions.
|
|
99
|
-
|
|
100
|
-
`options` is made of the following:
|
|
101
|
-
|
|
102
|
-
#### collection
|
|
103
|
-
|
|
104
|
-
The collection this module will create and use to store locks, by default `locks`
|
|
105
|
-
|
|
106
|
-
### .lock([action1[, action2[, action3[, ...])
|
|
107
|
-
|
|
108
|
-
Create a lock for the combination of said actions, return a Promise that is rejected if lock creation failed.
|
|
109
|
-
|
|
110
|
-
The lock's id will actually be the various arguments converted to string and joined with `"-"`, so passing objects
|
|
111
|
-
to this function is ill-advised.
|
|
112
|
-
|
|
113
|
-
If lock creation succeeds, the Promise resolves to a function to free the lock.
|
|
114
|
-
|
|
115
|
-
If lock creation fails, an exception is thrown.
|
|
116
|
-
|
|
117
|
-
### .free([action1[, action2[, action3[, ...])
|
|
118
|
-
|
|
119
|
-
Frees the lock. If you want to wait until the lock is freed, you can chain it with `.then`.
|
|
120
|
-
|
|
121
|
-
### .resfresh([action1[, action2[, action3[, ...])
|
|
122
|
-
|
|
123
|
-
Refreshes the lock, giving it one minute more. Chainable.
|
|
124
|
-
|
|
125
|
-
## MongoDb model
|
|
126
|
-
|
|
127
|
-
Model created:
|
|
128
|
-
|
|
129
|
-
``` js
|
|
130
|
-
// This module will create a Mongoose model
|
|
131
|
-
// collection with schema:
|
|
132
|
-
Locks = new mongoose.Schema({
|
|
133
|
-
createdAt: Date,
|
|
134
|
-
refreshedAt: Date, //indexed, expires after 60 seconds
|
|
135
|
-
action: String //uniquely indexed
|
|
136
|
-
});
|
|
58
|
+
const lockManager = new LockManager(mongoose.model("Lock").collection);
|
|
59
|
+
// ...
|
|
137
60
|
```
|
|
138
|
-
|
|
139
|
-
The collection is called "locks" by default, but you can set the name you want in the `options`
|
|
140
|
-
parameter of the `init()` function.
|
package/dist/index.js
CHANGED
|
@@ -10,47 +10,108 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.MongoLocksError = void 0;
|
|
13
|
-
const
|
|
13
|
+
const mongodb_1 = require("mongodb");
|
|
14
14
|
class MongoLocksError extends Error {
|
|
15
15
|
constructor(message) {
|
|
16
16
|
super(message);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
exports.MongoLocksError = MongoLocksError;
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
const makeKey = (key) => {
|
|
21
|
+
// Arrays mess up the unique MongoDB indexes
|
|
22
|
+
return Array.isArray(key) ? { _key_array: key } : key;
|
|
23
|
+
};
|
|
24
|
+
class Lock {
|
|
25
|
+
constructor(_id, action, collection, locked) {
|
|
26
|
+
this._id = _id;
|
|
27
|
+
this.action = action;
|
|
28
|
+
this.collection = collection;
|
|
29
|
+
this.locked = locked;
|
|
30
|
+
if (this.locked) {
|
|
31
|
+
(() => __awaiter(this, void 0, void 0, function* () {
|
|
32
|
+
while (this.locked) {
|
|
33
|
+
yield new Promise((resolve) => setTimeout(resolve, 10000));
|
|
34
|
+
yield this.refresh().catch(() => {
|
|
35
|
+
console.error("Failed to refresh lock", action);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}))();
|
|
39
|
+
}
|
|
26
40
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Instead of calling `this.free` directly you can use the `using` syntax
|
|
43
|
+
*
|
|
44
|
+
* @returns true if the lock was successfully released. False if the lock was not found
|
|
45
|
+
*/
|
|
46
|
+
free() {
|
|
47
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
+
if (!this.locked) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
const result = yield this.collection.deleteOne({ _id: this._id });
|
|
52
|
+
return result.deletedCount === 1;
|
|
53
|
+
});
|
|
30
54
|
}
|
|
31
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Refreshes the lock's TTL
|
|
57
|
+
*
|
|
58
|
+
* Automatically called every 10 seconds if the lock is still active, no
|
|
59
|
+
* need to call this manually
|
|
60
|
+
*
|
|
61
|
+
* @returns true if the lock was successfully refreshed. False if the lock was not found
|
|
62
|
+
*/
|
|
63
|
+
refresh() {
|
|
32
64
|
return __awaiter(this, void 0, void 0, function* () {
|
|
33
|
-
if (!this.
|
|
34
|
-
|
|
65
|
+
if (!this.locked) {
|
|
66
|
+
return false;
|
|
35
67
|
}
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
yield l.save();
|
|
40
|
-
return () => this.Locks.deleteOne({ action: lockId }).exec();
|
|
68
|
+
const res = yield this.collection.updateOne({ _id: this._id }, { $set: { refreshedAt: new Date(), expiresAt: new Date(Date.now() + 60000) } });
|
|
69
|
+
this.locked = res.matchedCount === 1;
|
|
70
|
+
return this.locked;
|
|
41
71
|
});
|
|
42
72
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
throw new MongoLocksError("You must initialize mongo-locks with a mongoose connection");
|
|
46
|
-
}
|
|
47
|
-
return this.Locks.updateOne({ action: makeLockId(actions) }, { $set: { refreshedAt: Date.now() } }, { upsert: true }).exec();
|
|
73
|
+
[Symbol.dispose]() {
|
|
74
|
+
this.free();
|
|
48
75
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
76
|
+
[Symbol.asyncDispose]() {
|
|
77
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
78
|
+
return this.free();
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
class LockManager {
|
|
83
|
+
constructor(collection) {
|
|
84
|
+
this.MongoLocksError = MongoLocksError;
|
|
85
|
+
this.collection = collection;
|
|
86
|
+
collection.createIndex({ action: 1 }, { unique: true });
|
|
87
|
+
collection.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Creates a DB lock based on the key provided
|
|
91
|
+
*
|
|
92
|
+
* @returns a function that when called will release the lock
|
|
93
|
+
*/
|
|
94
|
+
lock(key) {
|
|
95
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
96
|
+
const lockId = makeKey(key);
|
|
97
|
+
const id = new mongodb_1.ObjectId();
|
|
98
|
+
try {
|
|
99
|
+
yield this.collection.insertOne({
|
|
100
|
+
_id: id,
|
|
101
|
+
action: lockId,
|
|
102
|
+
createdAt: new Date(),
|
|
103
|
+
refreshedAt: new Date(),
|
|
104
|
+
expiresAt: new Date(Date.now() + 60000),
|
|
105
|
+
});
|
|
106
|
+
return new Lock(id, lockId, this.collection, true);
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
if (err instanceof Error && "code" in err && err.code === 11000) {
|
|
110
|
+
return new Lock(id, lockId, this.collection, false);
|
|
111
|
+
}
|
|
112
|
+
throw err;
|
|
113
|
+
}
|
|
114
|
+
});
|
|
54
115
|
}
|
|
55
116
|
}
|
|
56
|
-
exports.default =
|
|
117
|
+
exports.default = LockManager;
|
package/index.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import lockSchema from "./src/schema";
|
|
1
|
+
import { Collection, ObjectId } from "mongodb";
|
|
3
2
|
|
|
4
3
|
export class MongoLocksError extends Error {
|
|
5
4
|
constructor(message?: string) {
|
|
@@ -7,50 +6,123 @@ export class MongoLocksError extends Error {
|
|
|
7
6
|
}
|
|
8
7
|
}
|
|
9
8
|
|
|
10
|
-
const
|
|
9
|
+
const makeKey = (key: unknown) => {
|
|
10
|
+
// Arrays mess up the unique MongoDB indexes
|
|
11
|
+
return Array.isArray(key) ? { _key_array: key } : key;
|
|
12
|
+
};
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
interface LockModel {
|
|
15
|
+
_id: ObjectId;
|
|
16
|
+
action: unknown;
|
|
17
|
+
createdAt: Date;
|
|
18
|
+
refreshedAt: Date;
|
|
19
|
+
expiresAt: Date;
|
|
20
|
+
}
|
|
16
21
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
class Lock {
|
|
23
|
+
constructor(
|
|
24
|
+
public _id: ObjectId,
|
|
25
|
+
public action: unknown,
|
|
26
|
+
public collection: Collection<LockModel>,
|
|
27
|
+
public locked: boolean
|
|
28
|
+
) {
|
|
29
|
+
if (this.locked) {
|
|
30
|
+
(async () => {
|
|
31
|
+
while (this.locked) {
|
|
32
|
+
await new Promise((resolve) => setTimeout(resolve, 10_000));
|
|
33
|
+
await this.refresh().catch(() => {
|
|
34
|
+
console.error("Failed to refresh lock", action);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
})();
|
|
38
|
+
}
|
|
20
39
|
}
|
|
21
40
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Instead of calling `this.free` directly you can use the `using` syntax
|
|
43
|
+
*
|
|
44
|
+
* @returns true if the lock was successfully released. False if the lock was not found
|
|
45
|
+
*/
|
|
46
|
+
async free(): Promise<boolean> {
|
|
47
|
+
if (!this.locked) {
|
|
48
|
+
return false;
|
|
25
49
|
}
|
|
26
50
|
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
const l = new this.Locks();
|
|
30
|
-
l.action = lockId;
|
|
31
|
-
await l.save();
|
|
32
|
-
return () => this.Locks!.deleteOne({ action: lockId }).exec()
|
|
51
|
+
const result = await this.collection.deleteOne({ _id: this._id });
|
|
52
|
+
return result.deletedCount === 1;
|
|
33
53
|
}
|
|
34
54
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Refreshes the lock's TTL
|
|
57
|
+
*
|
|
58
|
+
* Automatically called every 10 seconds if the lock is still active, no
|
|
59
|
+
* need to call this manually
|
|
60
|
+
*
|
|
61
|
+
* @returns true if the lock was successfully refreshed. False if the lock was not found
|
|
62
|
+
*/
|
|
63
|
+
async refresh(): Promise<boolean> {
|
|
64
|
+
if (!this.locked) {
|
|
65
|
+
return false;
|
|
38
66
|
}
|
|
39
67
|
|
|
40
|
-
|
|
41
|
-
{
|
|
42
|
-
{ $set: { refreshedAt: Date.now() } }
|
|
43
|
-
|
|
44
|
-
|
|
68
|
+
const res = await this.collection.updateOne(
|
|
69
|
+
{ _id: this._id },
|
|
70
|
+
{ $set: { refreshedAt: new Date(), expiresAt: new Date(Date.now() + 60_000) } }
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
this.locked = res.matchedCount === 1;
|
|
74
|
+
|
|
75
|
+
return this.locked;
|
|
45
76
|
}
|
|
46
77
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
78
|
+
[Symbol.dispose]() {
|
|
79
|
+
this.free();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async [Symbol.asyncDispose]() {
|
|
83
|
+
return this.free();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
class LockManager {
|
|
88
|
+
collection: Collection<LockModel>;
|
|
89
|
+
MongoLocksError = MongoLocksError;
|
|
90
|
+
|
|
91
|
+
constructor(collection: Collection) {
|
|
92
|
+
this.collection = collection as unknown as Collection<LockModel>;
|
|
51
93
|
|
|
52
|
-
|
|
94
|
+
collection.createIndex({ action: 1 }, { unique: true });
|
|
95
|
+
collection.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Creates a DB lock based on the key provided
|
|
100
|
+
*
|
|
101
|
+
* @returns a function that when called will release the lock
|
|
102
|
+
*/
|
|
103
|
+
async lock(key: unknown): Promise<Lock> {
|
|
104
|
+
const lockId = makeKey(key);
|
|
105
|
+
const id = new ObjectId();
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
await this.collection.insertOne({
|
|
109
|
+
_id: id,
|
|
110
|
+
action: lockId,
|
|
111
|
+
createdAt: new Date(),
|
|
112
|
+
refreshedAt: new Date(),
|
|
113
|
+
expiresAt: new Date(Date.now() + 60_000),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
return new Lock(id, lockId, this.collection, true);
|
|
117
|
+
} catch (err) {
|
|
118
|
+
if (err instanceof Error && "code" in err && err.code === 11000) {
|
|
119
|
+
return new Lock(id, lockId, this.collection, false);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
throw err;
|
|
123
|
+
}
|
|
53
124
|
}
|
|
54
125
|
}
|
|
55
126
|
|
|
56
|
-
export default
|
|
127
|
+
export default LockManager;
|
|
128
|
+
export type { LockModel, Lock };
|
package/package.json
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongo-locks",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Simple and bountiful locks to avoid doing the same operation multiple times",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
+
"prepublishOnly": "npm run clean && tsc",
|
|
9
|
+
"clean": "rm -Rf dist"
|
|
10
|
+
},
|
|
6
11
|
"repository": {
|
|
7
12
|
"type": "git",
|
|
8
13
|
"url": "git+https://github.com/coyotte508/mongo-locks.git"
|
|
9
14
|
},
|
|
10
15
|
"keywords": [
|
|
11
16
|
"mongo",
|
|
12
|
-
"
|
|
17
|
+
"mongodb",
|
|
13
18
|
"lock",
|
|
14
19
|
"mutex",
|
|
15
20
|
"multiple"
|
|
@@ -21,21 +26,17 @@
|
|
|
21
26
|
},
|
|
22
27
|
"homepage": "https://github.com/coyotte508/mongo-locks#readme",
|
|
23
28
|
"peerDependencies": {
|
|
24
|
-
"
|
|
29
|
+
"mongodb": ">=4"
|
|
25
30
|
},
|
|
26
31
|
"devDependencies": {
|
|
27
|
-
"
|
|
28
|
-
"
|
|
32
|
+
"@types/node": "^20.12.7",
|
|
33
|
+
"mongodb": "^6.5.0",
|
|
34
|
+
"typescript": "^5.4.5"
|
|
29
35
|
},
|
|
30
36
|
"files": [
|
|
31
|
-
"src",
|
|
32
37
|
"dist",
|
|
33
38
|
"index.d.ts",
|
|
34
39
|
"index.ts",
|
|
35
40
|
"tsconfig.json"
|
|
36
|
-
]
|
|
37
|
-
|
|
38
|
-
"test": "echo \"Error: no test specified\" && exit 1",
|
|
39
|
-
"clean": "rm -Rf dist"
|
|
40
|
-
}
|
|
41
|
-
}
|
|
41
|
+
]
|
|
42
|
+
}
|
package/dist/src/schema.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const mongoose = require("mongoose");
|
|
4
|
-
const Schema = mongoose.Schema;
|
|
5
|
-
// define the schema for our user model
|
|
6
|
-
const lockSchema = new Schema({
|
|
7
|
-
createdAt: {
|
|
8
|
-
type: Date,
|
|
9
|
-
default: Date.now
|
|
10
|
-
},
|
|
11
|
-
refreshedAt: {
|
|
12
|
-
type: Date,
|
|
13
|
-
default: Date.now,
|
|
14
|
-
// Locks are not supposed to last longer than a minute
|
|
15
|
-
expires: 60
|
|
16
|
-
},
|
|
17
|
-
action: {
|
|
18
|
-
type: String,
|
|
19
|
-
unique: true,
|
|
20
|
-
required: true
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
exports.default = lockSchema;
|
package/src/schema.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import * as mongoose from "mongoose";
|
|
2
|
-
const Schema = mongoose.Schema;
|
|
3
|
-
|
|
4
|
-
// define the schema for our user model
|
|
5
|
-
const lockSchema = new Schema({
|
|
6
|
-
createdAt: {
|
|
7
|
-
type: Date,
|
|
8
|
-
default: Date.now
|
|
9
|
-
},
|
|
10
|
-
refreshedAt: {
|
|
11
|
-
type: Date,
|
|
12
|
-
default: Date.now,
|
|
13
|
-
// Locks are not supposed to last longer than a minute
|
|
14
|
-
expires: 60
|
|
15
|
-
},
|
|
16
|
-
action: {
|
|
17
|
-
type: String,
|
|
18
|
-
unique: true,
|
|
19
|
-
required: true
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
export default lockSchema;
|