@prosopo/client-example-server 2.7.122 → 2.7.123

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.
@@ -1,255 +1,185 @@
1
- import { blake2b } from "@noble/hashes/blake2b";
2
- import { u8aToHex } from "@polkadot/util";
3
- import { randomAsHex } from "@polkadot/util-crypto";
4
1
  import { ProsopoEnvError } from "@prosopo/common";
5
- import { getPair } from "@prosopo/keyring";
6
2
  import { getLogger } from "@prosopo/logger";
7
3
  import { ProsopoServer } from "@prosopo/server";
8
- import { ProcaptchaResponse, CaptchaType, ApiParams } from "@prosopo/types";
9
4
  import { at } from "@prosopo/util";
5
+ import { blake2b } from "@noble/hashes/blake2b";
6
+ import { u8aToHex } from "@polkadot/util";
7
+ import { randomAsHex } from "@polkadot/util-crypto";
8
+ import { getPair } from "@prosopo/keyring";
9
+ import { ApiParams, CaptchaType, ProcaptchaResponse } from "@prosopo/types";
10
10
  import jwt from "jsonwebtoken";
11
11
  import { z } from "zod";
12
- const logger = getLogger("info", "client-example-server:auth");
13
- const SubscribeBodySpec = ProcaptchaResponse.merge(
14
- z.object({
15
- email: z.string().email(),
16
- password: z.string(),
17
- siteKey: z.string()
18
- })
19
- );
12
+ //#region src/controllers/auth.ts
13
+ var logger = getLogger("info", "client-example-server:auth");
14
+ var SubscribeBodySpec = ProcaptchaResponse.merge(z.object({
15
+ email: z.string().email(),
16
+ password: z.string(),
17
+ siteKey: z.string()
18
+ }));
20
19
  function hashPassword(password) {
21
- return u8aToHex(blake2b(password));
20
+ return u8aToHex(blake2b(password));
22
21
  }
23
- const NO_IP = "NO_IP";
24
- const getPairAndSecretForSiteKey = (baseSecret, siteKey) => {
25
- let pair;
26
- let secret = baseSecret;
27
- pair = getPair(secret);
28
- if (pair.address === siteKey) {
29
- logger.info(() => ({
30
- msg: "Site key matches the server configuration without captcha type suffix",
31
- data: {
32
- siteKeyDerived: pair?.address,
33
- siteKey
34
- }
35
- }));
36
- return { pair, secret };
37
- }
38
- for (const captchaType of [
39
- CaptchaType.pow,
40
- CaptchaType.image,
41
- CaptchaType.frictionless,
42
- CaptchaType.puzzle
43
- ]) {
44
- const newSecret = `${baseSecret}//${captchaType}`;
45
- pair = getPair(newSecret);
46
- console.log(
47
- `[PAIR CHECK] Checking pair for ${captchaType}: ${pair?.address} (expected: ${siteKey})`
48
- );
49
- logger.info(() => ({
50
- msg: "Checking pair",
51
- data: {
52
- captchaType,
53
- siteKeyDerived: pair?.address,
54
- siteKey
55
- }
56
- }));
57
- if (pair.address === siteKey) {
58
- console.log(`[PAIR CHECK] ✅ Match found for ${captchaType}!`);
59
- secret = newSecret;
60
- break;
61
- }
62
- }
63
- if (!pair || pair.address !== siteKey) {
64
- throw new Error(
65
- `Site key does not match the server configuration: Provided ${siteKey} vs Server ${pair?.address}`
66
- );
67
- }
68
- return { pair, secret };
69
- };
70
- const getResponse = async (ip, token, secret, verifyEndpoint, email) => {
71
- const body = {
72
- [ApiParams.token]: token,
73
- [ApiParams.secret]: secret,
74
- ...email ? { [ApiParams.email]: email } : {}
75
- };
76
- if (process.env.NODE_ENV !== "development") {
77
- body[ApiParams.ip] = ip;
78
- }
79
- logger.info(() => ({
80
- data: {
81
- body
82
- }
83
- }));
84
- const response = await fetch(verifyEndpoint, {
85
- method: "POST",
86
- body: JSON.stringify(body)
87
- });
88
- return response.json();
22
+ var NO_IP = "NO_IP";
23
+ /**
24
+ * Derives the correct KeyringPair and secret for a given site key by trying different captcha types.
25
+ * @param baseSecret - The base secret from config
26
+ * @param siteKey - The site key to match against
27
+ * @returns Object containing the matched pair and its corresponding secret
28
+ * @throws Error if no matching pair is found
29
+ */
30
+ var getPairAndSecretForSiteKey = (baseSecret, siteKey) => {
31
+ let pair;
32
+ let secret = baseSecret;
33
+ pair = getPair(secret);
34
+ if (pair.address === siteKey) {
35
+ logger.info(() => ({
36
+ msg: "Site key matches the server configuration without captcha type suffix",
37
+ data: {
38
+ siteKeyDerived: pair?.address,
39
+ siteKey
40
+ }
41
+ }));
42
+ return {
43
+ pair,
44
+ secret
45
+ };
46
+ }
47
+ for (const captchaType of [
48
+ CaptchaType.pow,
49
+ CaptchaType.image,
50
+ CaptchaType.frictionless,
51
+ CaptchaType.puzzle
52
+ ]) {
53
+ const newSecret = `${baseSecret}//${captchaType}`;
54
+ pair = getPair(newSecret);
55
+ console.log(`[PAIR CHECK] Checking pair for ${captchaType}: ${pair?.address} (expected: ${siteKey})`);
56
+ logger.info(() => ({
57
+ msg: "Checking pair",
58
+ data: {
59
+ captchaType,
60
+ siteKeyDerived: pair?.address,
61
+ siteKey
62
+ }
63
+ }));
64
+ if (pair.address === siteKey) {
65
+ console.log(`[PAIR CHECK] ✅ Match found for ${captchaType}!`);
66
+ secret = newSecret;
67
+ break;
68
+ }
69
+ }
70
+ if (!pair || pair.address !== siteKey) throw new Error(`Site key does not match the server configuration: Provided ${siteKey} vs Server ${pair?.address}`);
71
+ return {
72
+ pair,
73
+ secret
74
+ };
89
75
  };
90
- const verify = async (prosopoServer, verifyType, verifyEndpoint, token, secret, ip, email) => {
91
- if (verifyType === "api") {
92
- logger.info(() => ({
93
- msg: "Verifying using the API endpoint",
94
- data: {
95
- verifyEndpoint
96
- }
97
- }));
98
- const response = await getResponse(
99
- ip,
100
- token,
101
- secret,
102
- verifyEndpoint,
103
- email
104
- );
105
- logger.info(() => ({
106
- data: {
107
- response
108
- }
109
- }));
110
- return response.verified;
111
- }
112
- const verified = await prosopoServer.isVerified(token, ip, email);
113
- logger.info(() => ({
114
- data: {
115
- verified
116
- }
117
- }));
118
- return verified[ApiParams.verified];
76
+ var getResponse = async (ip, token, secret, verifyEndpoint, email) => {
77
+ const body = {
78
+ [ApiParams.token]: token,
79
+ [ApiParams.secret]: secret,
80
+ ...email ? { [ApiParams.email]: email } : {}
81
+ };
82
+ if (process.env.NODE_ENV !== "development") body[ApiParams.ip] = ip;
83
+ logger.info(() => ({ data: { body } }));
84
+ return (await fetch(verifyEndpoint, {
85
+ method: "POST",
86
+ body: JSON.stringify(body)
87
+ })).json();
119
88
  };
120
- const signup = async (mongoose, config, verifyEndpoint, verifyType, req, res, next) => {
121
- try {
122
- if (!config.account.secret) {
123
- throw new ProsopoEnvError("GENERAL.MNEMONIC_UNDEFINED", {
124
- context: { missingParams: ["PROSOPO_SITE_PRIVATE_KEY"] }
125
- });
126
- }
127
- const User = mongoose.model("User");
128
- const dbUser = await User.findOne({
129
- email: { $eq: req.body.email }
130
- });
131
- const payload = SubscribeBodySpec.parse(req.body);
132
- const token = payload[ApiParams.procaptchaResponse];
133
- const siteKey = payload[ApiParams.siteKey];
134
- const { pair, secret } = getPairAndSecretForSiteKey(
135
- config.account.secret,
136
- siteKey
137
- );
138
- const prosopoServer = new ProsopoServer(config, pair);
139
- if (dbUser) {
140
- return res.status(409).json({ message: "email already exists" });
141
- }
142
- const email = req.body.email;
143
- const verified = await verify(
144
- prosopoServer,
145
- verifyType,
146
- verifyEndpoint,
147
- token,
148
- secret,
149
- req.headers["x-client-ip"]?.toString() || "127.0.0.1",
150
- email
151
- );
152
- if (verified === true) {
153
- const salt = randomAsHex(32);
154
- const passwordHash = hashPassword(`${req.body.password}${salt}`);
155
- if (passwordHash) {
156
- return User.create({
157
- email,
158
- name: req.body.name,
159
- password: passwordHash,
160
- salt
161
- }).then(() => {
162
- res.status(200).json({ message: "user created" });
163
- }).catch((err) => {
164
- logger.error(() => ({
165
- err,
166
- msg: "Error creating user in database"
167
- }));
168
- res.status(502).json({ message: "error while creating the user" });
169
- });
170
- }
171
- } else {
172
- res.status(401).json({ message: "user has not completed a captcha", verified });
173
- }
174
- } catch (err) {
175
- console.error("error", err);
176
- res.status(500).json({ message: err.message || "internal server error" });
177
- }
89
+ var verify = async (prosopoServer, verifyType, verifyEndpoint, token, secret, ip, email) => {
90
+ if (verifyType === "api") {
91
+ logger.info(() => ({
92
+ msg: "Verifying using the API endpoint",
93
+ data: { verifyEndpoint }
94
+ }));
95
+ const response = await getResponse(ip, token, secret, verifyEndpoint, email);
96
+ logger.info(() => ({ data: { response } }));
97
+ return response.verified;
98
+ }
99
+ const verified = await prosopoServer.isVerified(token, ip, email);
100
+ logger.info(() => ({ data: { verified } }));
101
+ return verified[ApiParams.verified];
178
102
  };
179
- const login = async (mongoose, config, verifyEndpoint, verifyType, req, res) => {
180
- const User = mongoose.model("User");
181
- await User.findOne({
182
- email: { $eq: req.body.email }
183
- }).then(async (dbUser) => {
184
- if (dbUser) {
185
- const payload = SubscribeBodySpec.parse(req.body);
186
- const token = payload[ApiParams.procaptchaResponse];
187
- const siteKey = payload[ApiParams.siteKey];
188
- if (!config.account.secret) {
189
- throw new ProsopoEnvError("GENERAL.SECRET_MISSING", {
190
- context: { missingParams: ["PROSOPO_SITE_PRIVATE_KEY"] }
191
- });
192
- }
193
- const { pair, secret } = getPairAndSecretForSiteKey(
194
- config.account.secret,
195
- siteKey
196
- );
197
- const prosopoServer = new ProsopoServer(config, pair);
198
- const verified = await verify(
199
- prosopoServer,
200
- verifyType,
201
- verifyEndpoint,
202
- token,
203
- secret,
204
- req.headers["x-client-ip"]?.toString() || NO_IP
205
- );
206
- logger.info(() => ({
207
- data: {
208
- verified
209
- }
210
- }));
211
- if (verified) {
212
- const passwordHash = hashPassword(
213
- `${req.body.password}${dbUser.salt}`
214
- );
215
- if (passwordHash !== dbUser.password) {
216
- return res.status(401).json({ message: "invalid credentials" });
217
- }
218
- const token2 = jwt.sign({ email: req.body.email }, "secret", {
219
- expiresIn: "1h"
220
- });
221
- return res.status(200).json({ message: "user logged in", token: token2 });
222
- }
223
- return res.status(401).json({ message: "user has not completed a captcha", verified });
224
- }
225
- return res.status(404).json({ message: "user not found" });
226
- }).catch((err) => {
227
- console.error("error", err);
228
- res.status(500).json({ message: err.message || "internal server error" });
229
- });
103
+ var signup = async (mongoose, config, verifyEndpoint, verifyType, req, res, next) => {
104
+ try {
105
+ if (!config.account.secret) throw new ProsopoEnvError("GENERAL.MNEMONIC_UNDEFINED", { context: { missingParams: ["PROSOPO_SITE_PRIVATE_KEY"] } });
106
+ const User = mongoose.model("User");
107
+ const dbUser = await User.findOne({ email: { $eq: req.body.email } });
108
+ const payload = SubscribeBodySpec.parse(req.body);
109
+ const token = payload[ApiParams.procaptchaResponse];
110
+ const siteKey = payload[ApiParams.siteKey];
111
+ const { pair, secret } = getPairAndSecretForSiteKey(config.account.secret, siteKey);
112
+ const prosopoServer = new ProsopoServer(config, pair);
113
+ if (dbUser) return res.status(409).json({ message: "email already exists" });
114
+ const email = req.body.email;
115
+ const verified = await verify(prosopoServer, verifyType, verifyEndpoint, token, secret, req.headers["x-client-ip"]?.toString() || "127.0.0.1", email);
116
+ if (verified === true) {
117
+ const salt = randomAsHex(32);
118
+ const passwordHash = hashPassword(`${req.body.password}${salt}`);
119
+ if (passwordHash) return User.create({
120
+ email,
121
+ name: req.body.name,
122
+ password: passwordHash,
123
+ salt
124
+ }).then(() => {
125
+ res.status(200).json({ message: "user created" });
126
+ }).catch((err) => {
127
+ logger.error(() => ({
128
+ err,
129
+ msg: "Error creating user in database"
130
+ }));
131
+ res.status(502).json({ message: "error while creating the user" });
132
+ });
133
+ } else res.status(401).json({
134
+ message: "user has not completed a captcha",
135
+ verified
136
+ });
137
+ } catch (err) {
138
+ console.error("error", err);
139
+ res.status(500).json({ message: err.message || "internal server error" });
140
+ }
230
141
  };
231
- const isAuth = (req, res) => {
232
- const authHeader = req.get("Authorization") || "";
233
- if (!authHeader) {
234
- res.status(401).json({ message: "not authenticated" });
235
- }
236
- const token = at(authHeader.split(" "), 1);
237
- let decodedToken = "";
238
- try {
239
- decodedToken = jwt.verify(token, "secret");
240
- } catch (err) {
241
- res.status(500).json({
242
- message: err.message || "could not decode the token"
243
- });
244
- }
245
- if (!decodedToken) {
246
- res.status(401).json({ message: "unauthorized" });
247
- } else {
248
- res.status(200).json({ message: "here is your resource" });
249
- }
142
+ var login = async (mongoose, config, verifyEndpoint, verifyType, req, res) => {
143
+ await mongoose.model("User").findOne({ email: { $eq: req.body.email } }).then(async (dbUser) => {
144
+ if (dbUser) {
145
+ const payload = SubscribeBodySpec.parse(req.body);
146
+ const token = payload[ApiParams.procaptchaResponse];
147
+ const siteKey = payload[ApiParams.siteKey];
148
+ if (!config.account.secret) throw new ProsopoEnvError("GENERAL.SECRET_MISSING", { context: { missingParams: ["PROSOPO_SITE_PRIVATE_KEY"] } });
149
+ const { pair, secret } = getPairAndSecretForSiteKey(config.account.secret, siteKey);
150
+ const verified = await verify(new ProsopoServer(config, pair), verifyType, verifyEndpoint, token, secret, req.headers["x-client-ip"]?.toString() || NO_IP);
151
+ logger.info(() => ({ data: { verified } }));
152
+ if (verified) {
153
+ if (hashPassword(`${req.body.password}${dbUser.salt}`) !== dbUser.password) return res.status(401).json({ message: "invalid credentials" });
154
+ const token = jwt.sign({ email: req.body.email }, "secret", { expiresIn: "1h" });
155
+ return res.status(200).json({
156
+ message: "user logged in",
157
+ token
158
+ });
159
+ }
160
+ return res.status(401).json({
161
+ message: "user has not completed a captcha",
162
+ verified
163
+ });
164
+ }
165
+ return res.status(404).json({ message: "user not found" });
166
+ }).catch((err) => {
167
+ console.error("error", err);
168
+ res.status(500).json({ message: err.message || "internal server error" });
169
+ });
250
170
  };
251
- export {
252
- isAuth,
253
- login,
254
- signup
171
+ var isAuth = (req, res) => {
172
+ const authHeader = req.get("Authorization") || "";
173
+ if (!authHeader) res.status(401).json({ message: "not authenticated" });
174
+ const token = at(authHeader.split(" "), 1);
175
+ let decodedToken = "";
176
+ try {
177
+ decodedToken = jwt.verify(token, "secret");
178
+ } catch (err) {
179
+ res.status(500).json({ message: err.message || "could not decode the token" });
180
+ }
181
+ if (!decodedToken) res.status(401).json({ message: "unauthorized" });
182
+ else res.status(200).json({ message: "here is your resource" });
255
183
  };
184
+ //#endregion
185
+ export { isAuth, login, signup };
@@ -6,11 +6,11 @@ export interface UserInterface {
6
6
  password: string;
7
7
  salt: string;
8
8
  }
9
- declare const UserSchema: mongoose.Schema<UserInterface, mongoose.Model<UserInterface, any, any, any, mongoose.Document<unknown, any, UserInterface> & UserInterface & {
9
+ declare const UserSchema: mongoose.Schema<UserInterface, mongoose.Model<UserInterface, any, any, any, mongoose.Document<unknown, any, UserInterface, any, {}> & UserInterface & {
10
10
  _id: mongoose.Types.ObjectId;
11
11
  } & {
12
12
  __v: number;
13
- }, any>, {}, {}, {}, {}, mongoose.DefaultSchemaOptions, UserInterface, mongoose.Document<unknown, {}, mongoose.FlatRecord<UserInterface>> & mongoose.FlatRecord<UserInterface> & {
13
+ }, any>, {}, {}, {}, {}, mongoose.DefaultSchemaOptions, UserInterface, mongoose.Document<unknown, {}, mongoose.FlatRecord<UserInterface>, {}, mongoose.DefaultSchemaOptions> & mongoose.FlatRecord<UserInterface> & {
14
14
  _id: mongoose.Types.ObjectId;
15
15
  } & {
16
16
  __v: number;
@@ -1,24 +1,20 @@
1
1
  import mongoose, { Schema } from "mongoose";
2
- const UserSchema = new Schema({
3
- email: {
4
- type: mongoose.SchemaTypes.String,
5
- required: true
6
- },
7
- name: {
8
- type: mongoose.SchemaTypes.String
9
- },
10
- password: {
11
- type: mongoose.SchemaTypes.String,
12
- required: true
13
- },
14
- id: {
15
- type: mongoose.SchemaTypes.Number
16
- },
17
- salt: {
18
- type: mongoose.SchemaTypes.String,
19
- required: true
20
- }
2
+ //#region src/models/user.ts
3
+ var UserSchema = new Schema({
4
+ email: {
5
+ type: mongoose.SchemaTypes.String,
6
+ required: true
7
+ },
8
+ name: { type: mongoose.SchemaTypes.String },
9
+ password: {
10
+ type: mongoose.SchemaTypes.String,
11
+ required: true
12
+ },
13
+ id: { type: mongoose.SchemaTypes.Number },
14
+ salt: {
15
+ type: mongoose.SchemaTypes.String,
16
+ required: true
17
+ }
21
18
  });
22
- export {
23
- UserSchema as default
24
- };
19
+ //#endregion
20
+ export { UserSchema as default };
@@ -1,27 +1,21 @@
1
+ import { isAuth, login, signup } from "../controllers/auth.js";
1
2
  import express from "express";
2
- import { login, signup, isAuth } from "../controllers/auth.js";
3
- const router = express.Router();
3
+ //#region src/routes/routes.ts
4
+ var router = express.Router();
4
5
  function getRoutes(mongoose, config, verifyEndpoint, verifyType) {
5
- router.post(
6
- "/login",
7
- login.bind(null, mongoose, config, verifyEndpoint, verifyType)
8
- );
9
- router.post(
10
- "/signup",
11
- signup.bind(null, mongoose, config, verifyEndpoint, verifyType)
12
- );
13
- router.get("/private", isAuth);
14
- router.get("/public", (req, res) => {
15
- res.status(200).json({ message: "here is your public resource" });
16
- });
17
- router.get("/health", (req, res) => {
18
- res.status(200).json({ status: "ok" });
19
- });
20
- router.use("/", (req, res) => {
21
- res.status(404).json({ error: "page not found" });
22
- });
23
- return router;
6
+ router.post("/login", login.bind(null, mongoose, config, verifyEndpoint, verifyType));
7
+ router.post("/signup", signup.bind(null, mongoose, config, verifyEndpoint, verifyType));
8
+ router.get("/private", isAuth);
9
+ router.get("/public", (req, res) => {
10
+ res.status(200).json({ message: "here is your public resource" });
11
+ });
12
+ router.get("/health", (req, res) => {
13
+ res.status(200).json({ status: "ok" });
14
+ });
15
+ router.use("/", (req, res) => {
16
+ res.status(404).json({ error: "page not found" });
17
+ });
18
+ return router;
24
19
  }
25
- export {
26
- getRoutes as default
27
- };
20
+ //#endregion
21
+ export { getRoutes as default };
@@ -1,25 +1,20 @@
1
+ import UserSchema from "../models/user.js";
1
2
  import { fileURLToPath } from "node:url";
2
3
  import { getMongoConnectionOptions } from "@prosopo/database";
3
4
  import { AutoIncrementID } from "@typegoose/auto-increment";
4
5
  import mongoose from "mongoose";
5
- import UserSchema from "../models/user.js";
6
+ //#region src/utils/connection.ts
6
7
  function connectionFactory(uri) {
7
- const appName = fileURLToPath(import.meta.url);
8
- const conn = mongoose.createConnection(
9
- uri,
10
- getMongoConnectionOptions({
11
- url: uri,
12
- appName
13
- })
14
- );
15
- if (!conn.models.user) {
16
- UserSchema.plugin(AutoIncrementID, {
17
- field: "id"
18
- });
19
- conn.model("User", UserSchema);
20
- }
21
- return conn;
8
+ const appName = fileURLToPath(import.meta.url);
9
+ const conn = mongoose.createConnection(uri, getMongoConnectionOptions({
10
+ url: uri,
11
+ appName
12
+ }));
13
+ if (!conn.models.user) {
14
+ UserSchema.plugin(AutoIncrementID, { field: "id" });
15
+ conn.model("User", UserSchema);
16
+ }
17
+ return conn;
22
18
  }
23
- export {
24
- connectionFactory as default
25
- };
19
+ //#endregion
20
+ export { connectionFactory as default };
@@ -1,10 +1,6 @@
1
+ //#region src/utils/database.ts
1
2
  async function memoryServerSetup() {
2
- const MongoMemoryServer = (await import("mongodb-memory-server")).MongoMemoryServer;
3
- const mongod = MongoMemoryServer.create();
4
- const memoryServer = await mongod;
5
- return memoryServer.getUri();
3
+ return (await (await import("mongodb-memory-server")).MongoMemoryServer.create()).getUri();
6
4
  }
7
- export {
8
- memoryServerSetup as default,
9
- memoryServerSetup
10
- };
5
+ //#endregion
6
+ export { memoryServerSetup as default, memoryServerSetup };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prosopo/client-example-server",
3
- "version": "2.7.122",
3
+ "version": "2.7.123",
4
4
  "description": "Backend for client-example",
5
5
  "main": "dist/app.js",
6
6
  "types": "dist/app.d.ts",
@@ -42,34 +42,34 @@
42
42
  "@noble/hashes": "1.8.0",
43
43
  "@polkadot/util": "13.5.7",
44
44
  "@polkadot/util-crypto": "13.5.7",
45
- "@prosopo/common": "3.1.47",
46
- "@prosopo/database": "3.15.19",
47
- "@prosopo/logger": "2.0.3",
48
- "@prosopo/dotenv": "3.0.49",
49
- "@prosopo/keyring": "2.9.60",
50
- "@prosopo/server": "2.10.40",
51
- "@prosopo/types": "4.9.12",
52
- "@prosopo/util": "3.3.4",
45
+ "@prosopo/common": "3.1.48",
46
+ "@prosopo/database": "3.15.20",
47
+ "@prosopo/logger": "2.0.4",
48
+ "@prosopo/dotenv": "3.0.50",
49
+ "@prosopo/keyring": "2.9.61",
50
+ "@prosopo/server": "2.10.41",
51
+ "@prosopo/types": "4.10.0",
52
+ "@prosopo/util": "3.3.5",
53
53
  "@typegoose/auto-increment": "4.13.0",
54
54
  "cors": "2.8.5",
55
55
  "express": "4.21.2",
56
56
  "jsonwebtoken": "9.0.2",
57
57
  "mongodb-memory-server": "10.3.0",
58
- "mongoose": "8.13.0",
58
+ "mongoose": "8.24.1",
59
59
  "zod": "3.23.8"
60
60
  },
61
61
  "devDependencies": {
62
- "@prosopo/config": "3.3.4",
62
+ "@prosopo/config": "3.3.5",
63
63
  "@types/jsonwebtoken": "9.0.6",
64
64
  "@types/node": "22.10.2",
65
- "@vitest/coverage-v8": "3.2.4",
65
+ "@vitest/coverage-v8": "4.1.10",
66
66
  "concurrently": "9.0.1",
67
67
  "del-cli": "6.0.0",
68
68
  "npm-run-all": "4.1.5",
69
69
  "tslib": "2.7.0",
70
70
  "tsx": "4.20.3",
71
71
  "typescript": "5.6.2",
72
- "vite": "6.4.1",
73
- "vitest": "3.2.4"
72
+ "vite": "8.1.5",
73
+ "vitest": "4.1.10"
74
74
  }
75
75
  }