diff --git a/.changeset/mongoose-package-creation.md b/.changeset/mongoose-package-creation.md new file mode 100644 index 0000000000..d4374eca6b --- /dev/null +++ b/.changeset/mongoose-package-creation.md @@ -0,0 +1,20 @@ +--- +"@prosopo/mongoose": minor +"@prosopo/database": minor +"@prosopo/types-database": minor +--- + +Create new @prosopo/mongoose package with standard middleware plugin and utilities. This package consolidates mongoose-related utilities and implements standard middleware as a Mongoose plugin for consistent data handling across the application. + +Key features: +- Centralized mongoose connection management with optimized timeout and heartbeat settings +- Standard middleware plugin for automatic timestamp management (createdAt, updatedAt) +- Version increment middleware for mutation operations +- Safe model creation using mongoose's overwriteModels flag +- Zod integration with enhanced validation +- All schemas created with helper functions have timestamps enabled by default + +Changes: +- New @prosopo/mongoose package with connection, middleware, schema, and zodMapper utilities +- Updated @prosopo/database to use createMongooseConnection() and getOrCreateModel() +- Updated @prosopo/types-database schemas to use newSchema() with automatic middleware application diff --git a/package-lock.json b/package-lock.json index c410c49f38..79bd0dd3fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -904,7 +904,8 @@ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "integration/frameworks/angular/angular-procaptcha-integration-demo/node_modules/@angular/build/node_modules/vite": { "version": "7.1.11", @@ -1004,7 +1005,6 @@ "integrity": "sha512-9BemvpFxA26yIVdu8ROffadMkEdlk/AQQ2Jb486w7RPkrvUQ0pbEJukhv9aryJvhbMopT66S5H/j4ipOUMzmzQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "7.28.3", "@jridgewell/sourcemap-codec": "^1.4.14", @@ -1038,7 +1038,6 @@ "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -1336,8 +1335,7 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, - "license": "0BSD", - "peer": true + "license": "0BSD" }, "integration/frameworks/angular/angular-procaptcha-integration-demo/node_modules/typescript": { "version": "5.8.3", @@ -1345,7 +1343,6 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -1360,7 +1357,6 @@ "integrity": "sha512-4JLXU0tD6OZNVqlwzm3HGEhAHufSiyv+skb7q0d2367VDMzrU1Q/ZeepvkcHH0rZie6uqEtTQQe0OEOOluH3Mg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -1464,7 +1460,6 @@ "integrity": "sha512-Fe7MIg2NWXoK+M4GtclxaYNoTdZX2U8f/Fd3N8zxtEMcRsvliJOnJ4oQtpx5kqMAuZVO4zY3wuIY1wAGXYCUbQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "7.28.3", "@jridgewell/sourcemap-codec": "^1.4.14", @@ -2297,7 +2292,6 @@ "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.10.tgz", "integrity": "sha512-12fEzvKbEqjqy1fSk9DMYlJz6dF1MJVXuC5BB+oWWJpd+2lfh4xJ62pkvvLGAICI89hfM5n9Cy5kWnXwnqPZsA==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2328,7 +2322,6 @@ "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.3.10.tgz", "integrity": "sha512-g99Qe+NOVo72OLxowVF9NjCckswWYHmvO7MgeiZTDJbTjF9tXH96dMx7AWq76/GUinV10sNzDysVW16NoAbCRQ==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2354,7 +2347,6 @@ "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.10.tgz", "integrity": "sha512-UV8CGoB5P3FmJciI3/I/n3L7C3NVgGh7bIlZ1BaB/qJDtv0Wq0rRAGwmT/Z3gwmrRtfHZWme7/CeQ2CYJmMyUQ==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -2437,7 +2429,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -4949,7 +4940,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -4972,7 +4962,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -5215,7 +5204,6 @@ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.1.tgz", "integrity": "sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.11.0", @@ -6347,7 +6335,6 @@ "integrity": "sha512-nqhDw2ZcAUrKNPwhjinJny903bRhI0rQhiDz1LksjeRxqa36i3l75+4iXbOy0rlDpLJGxqtgoPavQjmmyS5UJw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/checkbox": "^4.2.1", "@inquirer/confirm": "^5.1.14", @@ -7314,7 +7301,6 @@ "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", @@ -7548,7 +7534,6 @@ "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -8503,7 +8488,6 @@ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz", "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", "license": "MIT", - "peer": true, "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", @@ -8749,6 +8733,7 @@ "hasInstallScript": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "detect-libc": "^1.0.3", "is-glob": "^4.0.3", @@ -8790,6 +8775,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8810,6 +8796,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8830,6 +8817,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8850,6 +8838,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8870,6 +8859,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8890,6 +8880,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8910,6 +8901,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8930,6 +8922,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8950,6 +8943,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8970,6 +8964,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -8990,6 +8985,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -9010,6 +9006,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -9030,6 +9027,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 10.0.0" }, @@ -9044,6 +9042,7 @@ "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "license": "Apache-2.0", "optional": true, + "peer": true, "bin": { "detect-libc": "bin/detect-libc.js" }, @@ -9056,7 +9055,8 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", @@ -9129,7 +9129,6 @@ "integrity": "sha512-MljrPobN0ZWTpn++da9vOvt+Ex+NlqTlr/XT7zi9sqPtDJiQcYl+d29hFAgpaeTqbeQKZwz3WDE9xcEfLE8c5A==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@polkadot-api/json-rpc-provider": "0.0.1", "@polkadot-api/utils": "0.1.0" @@ -9147,7 +9146,6 @@ "resolved": "https://registry.npmjs.org/@polkadot/api/-/api-16.5.2.tgz", "integrity": "sha512-EOkxs7KTgcytIhIxlIhIMV8EQQ/5F3bFs4hIRIqVFPJhNQn3tbq130HiJbQmvOnlxa3PXCEu7XVoCL0zkV08YQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@polkadot/api-augment": "16.5.2", "@polkadot/api-base": "16.5.2", @@ -9359,7 +9357,6 @@ "resolved": "https://registry.npmjs.org/@polkadot/util/-/util-13.5.8.tgz", "integrity": "sha512-5xEfNoum/Ct+gYWN3AYvBQ8vq8KiS4HsY3BexPUPXvSXSx3Id/JYA5oFLYnkuRp8hwoQGjX0wqUJ6Hp8D8LHKw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@polkadot/x-bigint": "13.5.8", "@polkadot/x-global": "13.5.8", @@ -9465,7 +9462,6 @@ "resolved": "https://registry.npmjs.org/@polkadot/util/-/util-13.5.8.tgz", "integrity": "sha512-5xEfNoum/Ct+gYWN3AYvBQ8vq8KiS4HsY3BexPUPXvSXSx3Id/JYA5oFLYnkuRp8hwoQGjX0wqUJ6Hp8D8LHKw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@polkadot/x-bigint": "13.5.8", "@polkadot/x-global": "13.5.8", @@ -9688,7 +9684,6 @@ "resolved": "https://registry.npmjs.org/@polkadot/util/-/util-13.5.8.tgz", "integrity": "sha512-5xEfNoum/Ct+gYWN3AYvBQ8vq8KiS4HsY3BexPUPXvSXSx3Id/JYA5oFLYnkuRp8hwoQGjX0wqUJ6Hp8D8LHKw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@polkadot/x-bigint": "13.5.8", "@polkadot/x-global": "13.5.8", @@ -9860,7 +9855,6 @@ "resolved": "https://registry.npmjs.org/@polkadot/util/-/util-13.5.8.tgz", "integrity": "sha512-5xEfNoum/Ct+gYWN3AYvBQ8vq8KiS4HsY3BexPUPXvSXSx3Id/JYA5oFLYnkuRp8hwoQGjX0wqUJ6Hp8D8LHKw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@polkadot/x-bigint": "13.5.8", "@polkadot/x-global": "13.5.8", @@ -10125,7 +10119,6 @@ "resolved": "https://registry.npmjs.org/@polkadot/util/-/util-13.5.8.tgz", "integrity": "sha512-5xEfNoum/Ct+gYWN3AYvBQ8vq8KiS4HsY3BexPUPXvSXSx3Id/JYA5oFLYnkuRp8hwoQGjX0wqUJ6Hp8D8LHKw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@polkadot/x-bigint": "13.5.8", "@polkadot/x-global": "13.5.8", @@ -10217,7 +10210,6 @@ "resolved": "https://registry.npmjs.org/@polkadot/types/-/types-16.5.2.tgz", "integrity": "sha512-Lsie9bCE/CxmxG76bpYnRU4/UcRTi5q9zYPtAjt9GbgPpUSr17mMqsWAitq+qFYF29Bxo9EvAbFkj9QxoFWNsA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@polkadot/keyring": "^13.5.8", "@polkadot/types-augment": "16.5.2", @@ -10572,7 +10564,6 @@ "resolved": "https://registry.npmjs.org/@polkadot/util/-/util-13.5.8.tgz", "integrity": "sha512-5xEfNoum/Ct+gYWN3AYvBQ8vq8KiS4HsY3BexPUPXvSXSx3Id/JYA5oFLYnkuRp8hwoQGjX0wqUJ6Hp8D8LHKw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@polkadot/x-bigint": "13.5.8", "@polkadot/x-global": "13.5.8", @@ -10688,7 +10679,6 @@ "resolved": "https://registry.npmjs.org/@polkadot/util/-/util-13.5.8.tgz", "integrity": "sha512-5xEfNoum/Ct+gYWN3AYvBQ8vq8KiS4HsY3BexPUPXvSXSx3Id/JYA5oFLYnkuRp8hwoQGjX0wqUJ6Hp8D8LHKw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@polkadot/x-bigint": "13.5.8", "@polkadot/x-global": "13.5.8", @@ -11057,7 +11047,6 @@ "resolved": "https://registry.npmjs.org/@polkadot/wasm-util/-/wasm-util-7.5.2.tgz", "integrity": "sha512-DIKy6CMiPsbguU5nUHz/hnD05eZmkT7R/E70cotk+QMaQWT189syJ05Z/YGQD/JdPoRf4uVNA5xHCWLikmzwZQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "tslib": "^2.7.0" }, @@ -11130,7 +11119,6 @@ "resolved": "https://registry.npmjs.org/@polkadot/x-randomvalues/-/x-randomvalues-13.5.7.tgz", "integrity": "sha512-NEElpdu+Wqlr6USoh3abQfe0MaWlFlynPiqkA0/SJjK+0V0UOw0CyPwPgGrGa71/ju+1bsnu/ySshXqCR8HXTw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@polkadot/x-global": "13.5.7", "tslib": "^2.8.0" @@ -11351,6 +11339,10 @@ "resolved": "packages/locale", "link": true }, + "node_modules/@prosopo/mongoose": { + "resolved": "packages/mongoose", + "link": true + }, "node_modules/@prosopo/procaptcha": { "resolved": "packages/procaptcha", "link": true @@ -12935,7 +12927,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==", "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.19.2" } @@ -13836,7 +13827,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -13926,7 +13916,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -15001,7 +14990,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -15439,7 +15427,6 @@ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "readdirp": "^4.0.1" }, @@ -18168,7 +18155,6 @@ "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" @@ -18277,6 +18263,7 @@ "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "prr": "~1.0.1" }, @@ -18778,7 +18765,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "license": "MIT", - "peer": true, "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -20181,7 +20167,6 @@ "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", "license": "MIT", - "peer": true, "dependencies": { "@types/html-minifier-terser": "^6.0.0", "html-minifier-terser": "^6.0.2", @@ -20431,7 +20416,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.23.2" }, @@ -20571,6 +20555,7 @@ "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", "license": "MIT", "optional": true, + "peer": true, "bin": { "image-size": "bin/image-size.js" }, @@ -21696,8 +21681,7 @@ "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.6.0.tgz", "integrity": "sha512-niVlkeYVRwKFpmfWg6suo6H9CrNnydfBLEqefM5UjibYS+UoTjZdmvPJSiuyrRLGnFj1eYRhFd/ch+5hSlsFVA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/jest-diff": { "version": "29.7.0", @@ -21745,7 +21729,6 @@ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "devOptional": true, "license": "MIT", - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -22007,7 +21990,6 @@ "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@colors/colors": "1.5.0", "body-parser": "^1.19.0", @@ -22391,7 +22373,6 @@ "integrity": "sha512-kdTwsyRuncDfjEs0DlRILWNvxhDG/Zij4YLO4TMJgDLW+8OzpfkdPnRgrsRuY1o+oaxJGWsps5f/RVBgGmmN0w==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -22446,6 +22427,7 @@ "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "pify": "^4.0.1", "semver": "^5.6.0" @@ -22460,6 +22442,7 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "license": "MIT", "optional": true, + "peer": true, "bin": { "mime": "cli.js" }, @@ -22473,6 +22456,7 @@ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=6" } @@ -22483,6 +22467,7 @@ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "license": "ISC", "optional": true, + "peer": true, "bin": { "semver": "bin/semver" } @@ -22493,6 +22478,7 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "license": "BSD-3-Clause", "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -23730,7 +23716,6 @@ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.13.0.tgz", "integrity": "sha512-e/iYV1mPeOkg+SWAMHzt3t42/EZyER3OB1H2pjP9C3vQ+Qb5DMeV9Kb+YCUycKgScA3fbwL7dKG4EpinGlg21g==", "license": "MIT", - "peer": true, "dependencies": { "bson": "^6.10.3", "kareem": "2.6.3", @@ -23927,6 +23912,7 @@ "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "iconv-lite": "^0.6.3", "sax": "^1.2.4" @@ -23944,6 +23930,7 @@ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -26168,7 +26155,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -26508,7 +26494,8 @@ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "license": "MIT", - "optional": true + "optional": true, + "peer": true }, "node_modules/psl": { "version": "1.15.0", @@ -26692,7 +26679,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -27525,7 +27511,6 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -28096,7 +28081,6 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -28200,7 +28184,6 @@ "integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -28262,7 +28245,8 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.3.tgz", "integrity": "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==", "license": "BlueOak-1.0.0", - "optional": true + "optional": true, + "peer": true }, "node_modules/saxes": { "version": "6.0.0", @@ -28933,7 +28917,6 @@ "integrity": "sha512-F+qYmH4z2s2FK+CxGj8moYcd1ekSIKH8ywkdqlOz88Dat35iB1DIYL11aILN46YSGMzQW/lbJNS307zBSDN5Ig==", "devOptional": true, "license": "GPL-3.0-or-later WITH Classpath-exception-2.0", - "peer": true, "dependencies": { "ws": "^8.8.1" } @@ -29046,7 +29029,6 @@ "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" @@ -29463,7 +29445,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -29808,7 +29789,6 @@ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.43.6.tgz", "integrity": "sha512-RnyO9VXI85Bmsf4b8AuQFBKFYL3LKUl+ZrifOjvlrQoboAROj5IITVLK1yOXBjwUWUn2BI5cfmurktgCzuZ5QA==", "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", @@ -30031,7 +30011,6 @@ "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.14.0", @@ -30511,8 +30490,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/tsx": { "version": "4.20.3", @@ -30716,7 +30694,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -31104,7 +31081,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -31483,7 +31459,6 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", @@ -31846,7 +31821,6 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.102.1.tgz", "integrity": "sha512-7h/weGm9d/ywQ6qzJ+Xy+r9n/3qgp/thalBbpOi5i223dPXKi04IBtqPN9nTd+jBc7QKfvDbaBnFipYp4sJAUQ==", "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -32007,7 +31981,6 @@ "integrity": "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", @@ -32631,7 +32604,6 @@ "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", "devOptional": true, "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -33071,6 +33043,7 @@ "@polkadot/util": "13.5.7", "@prosopo/common": "3.1.23", "@prosopo/locale": "3.1.23", + "@prosopo/mongoose": "1.0.0", "@prosopo/redis-client": "1.0.8", "@prosopo/types": "3.6.1", "@prosopo/types-database": "4.0.3", @@ -33601,6 +33574,1135 @@ } } }, + "packages/mongoose": { + "name": "@prosopo/mongoose", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "@prosopo/common": "3.1.23", + "mongodb": "6.15.0", + "mongoose": "8.13.0", + "zod": "3.23.8" + }, + "devDependencies": { + "@prosopo/config": "3.1.23", + "@types/node": "22.10.2", + "@vitest/coverage-v8": "3.0.9", + "concurrently": "9.0.1", + "del-cli": "6.0.0", + "mongodb-memory-server": "10.0.0", + "npm-run-all": "4.1.5", + "tslib": "2.7.0", + "tsx": "4.20.3", + "typescript": "5.6.2", + "vite": "6.3.5", + "vitest": "3.0.9" + }, + "engines": { + "node": "20", + "npm": "10.8.2" + } + }, + "packages/mongoose/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz", + "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/android-arm": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz", + "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/android-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz", + "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/android-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz", + "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz", + "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/darwin-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz", + "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz", + "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz", + "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/linux-arm": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz", + "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/linux-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz", + "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/linux-ia32": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz", + "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/linux-loong64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz", + "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz", + "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz", + "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz", + "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/linux-s390x": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz", + "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/linux-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz", + "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz", + "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz", + "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz", + "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz", + "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz", + "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/sunos-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz", + "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/win32-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz", + "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/win32-ia32": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz", + "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@esbuild/win32-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz", + "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "packages/mongoose/node_modules/@prosopo/config/node_modules/@rollup/plugin-node-resolve": { + "version": "15.2.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", + "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", + "extraneous": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "packages/mongoose/node_modules/@prosopo/config/node_modules/@rollup/plugin-replace": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.7.tgz", + "integrity": "sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==", + "extraneous": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "packages/mongoose/node_modules/@prosopo/config/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "extraneous": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "packages/mongoose/node_modules/@prosopo/config/node_modules/rollup": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.12.0.tgz", + "integrity": "sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==", + "extraneous": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.12.0", + "@rollup/rollup-android-arm64": "4.12.0", + "@rollup/rollup-darwin-arm64": "4.12.0", + "@rollup/rollup-darwin-x64": "4.12.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.12.0", + "@rollup/rollup-linux-arm64-gnu": "4.12.0", + "@rollup/rollup-linux-arm64-musl": "4.12.0", + "@rollup/rollup-linux-riscv64-gnu": "4.12.0", + "@rollup/rollup-linux-x64-gnu": "4.12.0", + "@rollup/rollup-linux-x64-musl": "4.12.0", + "@rollup/rollup-win32-arm64-msvc": "4.12.0", + "@rollup/rollup-win32-ia32-msvc": "4.12.0", + "@rollup/rollup-win32-x64-msvc": "4.12.0", + "fsevents": "~2.3.2" + } + }, + "packages/mongoose/node_modules/@prosopo/config/node_modules/rollup-plugin-import-css": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-import-css/-/rollup-plugin-import-css-3.5.1.tgz", + "integrity": "sha512-cXgMPCUoDu64A2OFme4Is3eHmLiA54qTzxfvCbsORzro3C1adSe1fMMKUqfOUKTXROAPpW9PNDjpaGgPloGJOQ==", + "extraneous": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.4" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "rollup": "^2.x.x || ^3.x.x || ^4.x.x" + } + }, + "packages/mongoose/node_modules/@prosopo/config/node_modules/rollup-plugin-visualizer": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.12.0.tgz", + "integrity": "sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ==", + "extraneous": true, + "license": "MIT", + "dependencies": { + "open": "^8.4.0", + "picomatch": "^2.3.1", + "source-map": "^0.7.4", + "yargs": "^17.5.1" + }, + "bin": { + "rollup-plugin-visualizer": "dist/bin/cli.js" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "rollup": "2.x || 3.x || 4.x" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "packages/mongoose/node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true, + "license": "MIT" + }, + "packages/mongoose/node_modules/@types/node": { + "version": "22.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", + "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "packages/mongoose/node_modules/@vitest/coverage-v8": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.0.9.tgz", + "integrity": "sha512-15OACZcBtQ34keIEn19JYTVuMFTlFrClclwWjHo/IRPg/8ELpkgNTl0o7WLP9WO9XGH6+tip9CPYtEOrIDJvBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@bcoe/v8-coverage": "^1.0.2", + "debug": "^4.4.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magic-string": "^0.30.17", + "magicast": "^0.3.5", + "std-env": "^3.8.0", + "test-exclude": "^7.0.1", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "3.0.9", + "vitest": "3.0.9" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "packages/mongoose/node_modules/@vitest/expect": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.9.tgz", + "integrity": "sha512-5eCqRItYgIML7NNVgJj6TVCmdzE7ZVgJhruW0ziSQV4V7PvLkDL1bBkBdcTs/VuIz0IxPb5da1IDSqc1TR9eig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.0.9", + "@vitest/utils": "3.0.9", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/mongoose/node_modules/@vitest/pretty-format": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.9.tgz", + "integrity": "sha512-OW9F8t2J3AwFEwENg3yMyKWweF7oRJlMyHOMIhO5F3n0+cgQAJZBjNgrF8dLwFTEXl5jUqBLXd9QyyKv8zEcmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/mongoose/node_modules/@vitest/runner": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.9.tgz", + "integrity": "sha512-NX9oUXgF9HPfJSwl8tUZCMP1oGx2+Sf+ru6d05QjzQz4OwWg0psEzwY6VexP2tTHWdOkhKHUIZH+fS6nA7jfOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.0.9", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/mongoose/node_modules/@vitest/snapshot": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.9.tgz", + "integrity": "sha512-AiLUiuZ0FuA+/8i19mTYd+re5jqjEc2jZbgJ2up0VY0Ddyyxg/uUtBDpIFAy4uzKaQxOW8gMgBdAJJ2ydhu39A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.0.9", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/mongoose/node_modules/@vitest/spy": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.9.tgz", + "integrity": "sha512-/CcK2UDl0aQ2wtkp3YVWldrpLRNCfVcIOFGlVGKO4R5eajsH393Z1yiXLVQ7vWsj26JOEjeZI0x5sm5P4OGUNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/mongoose/node_modules/@vitest/utils": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.9.tgz", + "integrity": "sha512-ilHM5fHhZ89MCp5aAaM9uhfl1c2JdxVxl3McqsdVyVNN6JffnEen8UMCdRTzOhGXNQGo5GNL9QugHrz727Wnng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.0.9", + "loupe": "^3.1.3", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/mongoose/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "packages/mongoose/node_modules/esbuild": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz", + "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.8", + "@esbuild/android-arm": "0.25.8", + "@esbuild/android-arm64": "0.25.8", + "@esbuild/android-x64": "0.25.8", + "@esbuild/darwin-arm64": "0.25.8", + "@esbuild/darwin-x64": "0.25.8", + "@esbuild/freebsd-arm64": "0.25.8", + "@esbuild/freebsd-x64": "0.25.8", + "@esbuild/linux-arm": "0.25.8", + "@esbuild/linux-arm64": "0.25.8", + "@esbuild/linux-ia32": "0.25.8", + "@esbuild/linux-loong64": "0.25.8", + "@esbuild/linux-mips64el": "0.25.8", + "@esbuild/linux-ppc64": "0.25.8", + "@esbuild/linux-riscv64": "0.25.8", + "@esbuild/linux-s390x": "0.25.8", + "@esbuild/linux-x64": "0.25.8", + "@esbuild/netbsd-arm64": "0.25.8", + "@esbuild/netbsd-x64": "0.25.8", + "@esbuild/openbsd-arm64": "0.25.8", + "@esbuild/openbsd-x64": "0.25.8", + "@esbuild/openharmony-arm64": "0.25.8", + "@esbuild/sunos-x64": "0.25.8", + "@esbuild/win32-arm64": "0.25.8", + "@esbuild/win32-ia32": "0.25.8", + "@esbuild/win32-x64": "0.25.8" + } + }, + "packages/mongoose/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "packages/mongoose/node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "packages/mongoose/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/mongoose/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/mongoose/node_modules/mongodb-memory-server": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/mongodb-memory-server/-/mongodb-memory-server-10.0.0.tgz", + "integrity": "sha512-7Geo/s4lst/QHw+N8/stdnyb08xn68O0zbSee62jgoPfWOXfSPhX9a8OvyOY/o23oYk9ra2EpA2Oejenb3JKfw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "mongodb-memory-server-core": "10.0.0", + "tslib": "^2.6.3" + }, + "engines": { + "node": ">=16.20.1" + } + }, + "packages/mongoose/node_modules/mongodb-memory-server-core": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-10.0.0.tgz", + "integrity": "sha512-AdYi4nVqe3Pk95fRJ+DegbDdEfAG9wujNsVvJWbwh8+ZJd+d3JJK1PHxRyJ9rMvoczvlli5M30eMig7zBuF5pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-mutex": "^0.5.0", + "camelcase": "^6.3.0", + "debug": "^4.3.5", + "find-cache-dir": "^3.3.2", + "follow-redirects": "^1.15.6", + "https-proxy-agent": "^7.0.5", + "mongodb": "^6.7.0", + "new-find-package-json": "^2.0.0", + "semver": "^7.6.3", + "tar-stream": "^3.1.7", + "tslib": "^2.6.3", + "yauzl": "^3.1.3" + }, + "engines": { + "node": ">=16.20.1" + } + }, + "packages/mongoose/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/mongoose/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/mongoose/node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "packages/mongoose/node_modules/vite": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "packages/mongoose/node_modules/vite-node": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.9.tgz", + "integrity": "sha512-w3Gdx7jDcuT9cNn9jExXgOyKmf5UOTb6WMHz8LGAm54eS1Elf5OuBhCxl6zJxGhEeIkgsE1WbHuoL0mj/UXqXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.0", + "es-module-lexer": "^1.6.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "packages/mongoose/node_modules/vitest": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.9.tgz", + "integrity": "sha512-BbcFDqNyBlfSpATmTtXOAOj71RNKDDvjBM/uPfnxxVGrG+FSH2RQIwgeEngTaTkuU/h0ScFvf+tRcKfYXzBybQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "3.0.9", + "@vitest/mocker": "3.0.9", + "@vitest/pretty-format": "^3.0.9", + "@vitest/runner": "3.0.9", + "@vitest/snapshot": "3.0.9", + "@vitest/spy": "3.0.9", + "@vitest/utils": "3.0.9", + "chai": "^5.2.0", + "debug": "^4.4.0", + "expect-type": "^1.1.0", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinypool": "^1.0.2", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0", + "vite-node": "3.0.9", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.0.9", + "@vitest/ui": "3.0.9", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "packages/mongoose/node_modules/vitest/node_modules/@vitest/mocker": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.9.tgz", + "integrity": "sha512-ryERPIBOnvevAkTq+L1lD+DTFBRcjueL9lOUfXsLfwP92h4e+Heb+PjiqS3/OURWPtywfafK0kj++yDFjWUmrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.0.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, "packages/procaptcha": { "name": "@prosopo/procaptcha", "version": "2.9.18", @@ -34104,6 +35206,7 @@ "dependencies": { "@prosopo/common": "3.1.23", "@prosopo/locale": "3.1.23", + "@prosopo/mongoose": "1.0.0", "@prosopo/types": "3.6.1", "@prosopo/user-access-policy": "3.5.29", "mongoose": "8.13.0", diff --git a/packages/database/package.json b/packages/database/package.json index e4b3876dae..27bc395d93 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -37,6 +37,7 @@ "@polkadot/util": "13.5.7", "@prosopo/common": "3.1.23", "@prosopo/locale": "3.1.23", + "@prosopo/mongoose": "1.0.0", "@prosopo/redis-client": "1.0.8", "@prosopo/types": "3.6.1", "@prosopo/types-database": "4.0.3", diff --git a/packages/database/src/base/mongo.ts b/packages/database/src/base/mongo.ts index ddf2b4edbb..b6e8a718d0 100644 --- a/packages/database/src/base/mongo.ts +++ b/packages/database/src/base/mongo.ts @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. import { type Logger, ProsopoDBError, getLogger } from "@prosopo/common"; +import { createMongooseConnection } from "@prosopo/mongoose"; import type { IDatabase } from "@prosopo/types-database"; -import { ServerApiVersion } from "mongodb"; import mongoose, { type Connection } from "mongoose"; mongoose.set("strictQuery", false); @@ -98,70 +98,17 @@ export class MongoDatabase implements IDatabase { } // Start a new connection - this.connecting = new Promise((resolve, reject) => { - const connection = mongoose.createConnection(this.url, { - dbName: this.dbname, - serverApi: ServerApiVersion.v1, + this.connecting = (async () => { + const connection = await createMongooseConnection({ + url: this.url, + dbname: this.dbname, + logger: this.logger, }); - const onConnected = () => { - this.logger.debug(() => ({ - data: { mongoUrl: this.safeURL }, - msg: "Database connection opened", - })); - this.connected = true; - this.connection = connection; - this.connecting = undefined; - resolve(); - }; - - const onError = (err: unknown) => { - this.logger.error(() => ({ - err, - data: { mongoUrl: this.safeURL }, - msg: "Database error", - })); - this.connected = false; - this.connecting = undefined; - reject(err); - }; - - connection.once("open", onConnected); - connection.once("error", onError); - - // Optional: handle other events - connection.on("disconnected", () => { - this.connected = false; - this.logger.debug(() => ({ - data: { mongoUrl: this.safeURL }, - msg: "Database disconnected", - })); - }); - - connection.on("reconnected", () => { - this.connected = true; - this.logger.debug(() => ({ - data: { mongoUrl: this.safeURL }, - msg: "Database reconnected", - })); - }); - - connection.on("close", () => { - this.connected = false; - this.logger.debug(() => ({ - data: { mongoUrl: this.safeURL }, - msg: "Database connection closed", - })); - }); - - connection.on("fullsetup", () => { - this.connected = true; - this.logger.debug(() => ({ - data: { mongoUrl: this.safeURL }, - msg: "Database connection is fully setup", - })); - }); - }); + this.connected = true; + this.connection = connection; + this.connecting = undefined; + })(); return this.connecting; } catch (e) { diff --git a/packages/database/src/databases/captcha.ts b/packages/database/src/databases/captcha.ts index 652f8b9883..13f448039c 100644 --- a/packages/database/src/databases/captcha.ts +++ b/packages/database/src/databases/captcha.ts @@ -13,6 +13,7 @@ // limitations under the License. import { type Logger, ProsopoDBError, getLogger } from "@prosopo/common"; +import { getOrCreateModel } from "@prosopo/mongoose"; import { type CaptchaProperties, type ICaptchaDatabase, @@ -73,7 +74,12 @@ export class CaptchaDatabase extends MongoDatabase implements ICaptchaDatabase { CAPTCHA_TABLES.map(({ collectionName, modelName, schema }) => { if (this.connection) { - this.tables[collectionName] = this.connection.model(modelName, schema); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this.tables[collectionName] = getOrCreateModel( + this.connection, + modelName, + schema as any, + ); } }); } diff --git a/packages/database/src/databases/client.ts b/packages/database/src/databases/client.ts index 8d16fb92e7..2c0febc172 100644 --- a/packages/database/src/databases/client.ts +++ b/packages/database/src/databases/client.ts @@ -13,6 +13,7 @@ // limitations under the License. import { type Logger, ProsopoDBError } from "@prosopo/common"; +import { getOrCreateModel } from "@prosopo/mongoose"; import type { Timestamp } from "@prosopo/types"; import { AccountSchema, @@ -48,7 +49,12 @@ export class ClientDatabase extends MongoDatabase implements IClientDatabase { await super.connect(); CLIENT_TABLES.map(({ collectionName, modelName, schema }) => { if (this.connection) { - this.tables[collectionName] = this.connection.model(modelName, schema); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this.tables[collectionName] = getOrCreateModel( + this.connection, + modelName, + schema as any, + ); } }); } diff --git a/packages/database/src/databases/provider.ts b/packages/database/src/databases/provider.ts index 01cd0c7d57..ccda4c83b4 100644 --- a/packages/database/src/databases/provider.ts +++ b/packages/database/src/databases/provider.ts @@ -15,6 +15,7 @@ import { isHex } from "@polkadot/util/is"; import { type Logger, ProsopoDBError } from "@prosopo/common"; import type { TranslationKey } from "@prosopo/locale"; +import { getOrCreateModel } from "@prosopo/mongoose"; import { type RedisConnection, connectToRedis, @@ -240,7 +241,12 @@ export class ProviderDatabase const tables = {} as Tables; PROVIDER_TABLES.map(({ collectionName, modelName, schema }) => { if (this.connection) { - tables[collectionName] = this.connection.model(modelName, schema); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + tables[collectionName] = getOrCreateModel( + this.connection, + modelName, + schema as any, + ); } }); this.tables = tables; diff --git a/packages/mongoose/CHANGELOG.md b/packages/mongoose/CHANGELOG.md new file mode 100644 index 0000000000..39bd960045 --- /dev/null +++ b/packages/mongoose/CHANGELOG.md @@ -0,0 +1,15 @@ +# @prosopo/mongoose + +## 1.0.0 + +### Major Changes + +- Initial release of the Mongoose utilities package +- Added `createMongooseConnection()` for creating MongoDB connections +- Added standard middleware for automatic timestamp management (createdAt, updatedAt) +- Added version increment middleware for all mutating operations +- Added `createSchemaWithMiddleware()` for creating schemas with middleware pre-applied +- Added `getOrCreateModel()` for safe model creation that handles multiple calls +- Added `createSchemaBuilder()` for fluent schema and model creation +- Added `createModelFromZodSchema()` for Zod-to-Mongoose schema mapping with validation +- Added comprehensive test coverage diff --git a/packages/mongoose/README.md b/packages/mongoose/README.md new file mode 100644 index 0000000000..450b11ba25 --- /dev/null +++ b/packages/mongoose/README.md @@ -0,0 +1,55 @@ +# @prosopo/mongoose + +Mongoose utilities and middleware for Prosopo packages. + +This package provides: +- Mongoose connection management utilities +- Standard middleware plugin for timestamp management (createdAt, updatedAt) +- Version increment middleware for mutation operations +- Schema and model builders with automatic middleware application via plugin +- Zod-to-Mongoose schema mapping with validation +- Model caching to support multiple `.model()` calls + +## Features + +### Automatic Middleware Plugin +All schemas created with this package automatically include the standard middleware plugin: +- Version increment (`__v`) on all mutating operations +- `createdAt` timestamp (set once on creation, never overwritten) +- `updatedAt` timestamp (updated on every mutation) +- Validation enabled on all update operations + +The middleware is applied as a Mongoose plugin, which is the recommended approach for extending schema functionality. + +### Zod Integration +Convert Zod schemas to Mongoose schemas with automatic validation in pre and post middleware. + +## Usage + +### Creating Schemas with newSchema() + +```typescript +import { newSchema } from '@prosopo/mongoose'; + +// The standard middleware plugin is automatically applied +const UserSchema = newSchema({ + name: { type: String, required: true }, + email: { type: String, required: true } +}); +``` + +### Using the Plugin Directly + +You can also apply the standard middleware plugin to existing schemas: + +```typescript +import { Schema } from 'mongoose'; +import { standardMiddlewarePlugin } from '@prosopo/mongoose'; + +const MySchema = new Schema({ + field: String +}); + +// Apply the plugin +MySchema.plugin(standardMiddlewarePlugin); +``` diff --git a/packages/mongoose/package.json b/packages/mongoose/package.json new file mode 100644 index 0000000000..1ba85e861a --- /dev/null +++ b/packages/mongoose/package.json @@ -0,0 +1,62 @@ +{ + "name": "@prosopo/mongoose", + "version": "1.0.0", + "author": "PROSOPO LIMITED ", + "license": "Apache-2.0", + "private": false, + "engines": { + "node": "20", + "npm": "10.8.2" + }, + "scripts": { + "clean": "del-cli --verbose dist tsconfig.tsbuildinfo", + "build": "NODE_ENV=${NODE_ENV:-development}; vite build --config vite.esm.config.ts --mode $NODE_ENV", + "build:tsc": "tsc --build --verbose", + "build:cjs": "NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV", + "typecheck": "tsc --project tsconfig.types.json", + "test": "NODE_ENV=${NODE_ENV:-test}; npx vitest run --config ./vite.test.config.ts" + }, + "main": "dist/index.js", + "type": "module", + "exports": { + ".": { + "types": "dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/cjs/index.cjs" + } + }, + "types": "dist/index.d.ts", + "dependencies": { + "@prosopo/common": "3.1.23", + "mongodb": "6.15.0", + "mongoose": "8.13.0", + "zod": "3.23.8" + }, + "devDependencies": { + "@prosopo/config": "3.1.23", + "@types/node": "22.10.2", + "@vitest/coverage-v8": "3.0.9", + "concurrently": "9.0.1", + "del-cli": "6.0.0", + "mongodb-memory-server": "10.0.0", + "npm-run-all": "4.1.5", + "tslib": "2.7.0", + "tsx": "4.20.3", + "typescript": "5.6.2", + "vite": "6.3.5", + "vitest": "3.0.9" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/prosopo/captcha.git" + }, + "bugs": { + "url": "https://github.com/prosopo/captcha/issues" + }, + "homepage": "https://github.com/prosopo/captcha#readme", + "publishConfig": { + "registry": "https://registry.npmjs.org" + }, + "description": "Mongoose utilities and middleware for Prosopo packages", + "sideEffects": false +} diff --git a/packages/mongoose/src/connection.ts b/packages/mongoose/src/connection.ts new file mode 100644 index 0000000000..d6204dc30b --- /dev/null +++ b/packages/mongoose/src/connection.ts @@ -0,0 +1,117 @@ +// Copyright 2021-2025 Prosopo (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { type Logger, getLogger } from "@prosopo/common"; +import { ServerApiVersion } from "mongodb"; +import mongoose, { type Connection } from "mongoose"; + +mongoose.set("strictQuery", false); + +const DEFAULT_ENDPOINT = "mongodb://127.0.0.1:27017"; + +export interface MongooseConnectionOptions { + url?: string; + dbname?: string; + authSource?: string; + logger?: Logger; +} + +/** + * Creates and manages a mongoose connection to MongoDB + * @param options Connection options + * @returns Promise that resolves to the mongoose Connection + */ +export async function createMongooseConnection( + options: MongooseConnectionOptions, +): Promise { + const logger = options.logger || getLogger("info", import.meta.url); + const baseEndpoint = options.url || DEFAULT_ENDPOINT; + const parsedUrl = new URL(baseEndpoint); + + if (options.dbname) { + parsedUrl.pathname = options.dbname; + } + if (options.authSource) { + parsedUrl.searchParams.set("authSource", options.authSource); + } + + const connectionUrl = parsedUrl.toString(); + const safeURL = connectionUrl.replace(/\w+:\w+/, ""); + const dbname = options.dbname || parsedUrl.pathname.replace("/", ""); + + logger.debug(() => ({ + data: { mongoUrl: safeURL }, + msg: "Creating new mongoose connection", + })); + + // Create new connection promise + return new Promise((resolve, reject) => { + const connection = mongoose.createConnection(connectionUrl, { + dbName: dbname, + serverApi: ServerApiVersion.v1, + socketTimeoutMS: 30000, // 30 seconds + heartbeatFrequencyMS: 10000, // 10 seconds + }); + + const onConnected = () => { + logger.debug(() => ({ + data: { mongoUrl: safeURL }, + msg: "Mongoose connection connected", + })); + resolve(connection); + }; + + const onError = (err: unknown) => { + logger.error(() => ({ + err, + data: { mongoUrl: safeURL }, + msg: "Mongoose connection error", + })); + reject(err); + }; + + // Wait for 'connected' event instead of 'open' + connection.once("connected", onConnected); + connection.once("error", onError); + + // Handle other events + connection.on("disconnected", () => { + logger.debug(() => ({ + data: { mongoUrl: safeURL }, + msg: "Mongoose disconnected", + })); + }); + + connection.on("reconnected", () => { + logger.debug(() => ({ + data: { mongoUrl: safeURL }, + msg: "Mongoose reconnected", + })); + }); + + connection.on("close", () => { + logger.debug(() => ({ + data: { mongoUrl: safeURL }, + msg: "Mongoose connection closed", + })); + }); + + connection.on("fullsetup", () => { + logger.debug(() => ({ + data: { mongoUrl: safeURL }, + msg: "Mongoose connection is fully setup", + })); + }); + }); +} diff --git a/packages/mongoose/src/index.ts b/packages/mongoose/src/index.ts new file mode 100644 index 0000000000..6115d477d4 --- /dev/null +++ b/packages/mongoose/src/index.ts @@ -0,0 +1,29 @@ +// Copyright 2021-2025 Prosopo (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export { + createMongooseConnection, + type MongooseConnectionOptions, +} from "./connection.js"; +export { applyStandardMiddleware, standardMiddlewarePlugin } from "./middleware.js"; +export { + createSchemaBuilder, + createSchemaWithMiddleware, + getOrCreateModel, + newSchema, +} from "./schema.js"; +export { + createModelFromZodSchema, + zodToMongooseSchema, +} from "./zodMapper.js"; diff --git a/packages/mongoose/src/middleware.ts b/packages/mongoose/src/middleware.ts new file mode 100644 index 0000000000..114e0de785 --- /dev/null +++ b/packages/mongoose/src/middleware.ts @@ -0,0 +1,155 @@ +// Copyright 2021-2025 Prosopo (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { Query, Schema } from "mongoose"; + +interface TimestampedDocument { + createdAt?: Date; + updatedAt?: Date; +} + +/** + * Mongoose plugin that adds standard middleware to a schema: + * - Increments __v on all mutating operations + * - Sets createdAt only on creation + * - Updates updatedAt on all mutations + * - Ensures validation runs on update operations + * + * @param schema The mongoose schema to add middleware to + * @param options Optional plugin options (currently unused) + */ +export function standardMiddlewarePlugin(schema: Schema, options?: unknown): void { + // Add timestamps if they don't already exist + if (!schema.path("createdAt")) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + schema.add({ createdAt: { type: Date } } as any); + } + if (!schema.path("updatedAt")) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + schema.add({ updatedAt: { type: Date } } as any); + } + + // Pre-save middleware for new documents + schema.pre("save", function (next) { + const now = new Date(); + const doc = this as unknown as TimestampedDocument; + doc.updatedAt = now; + + // Only set createdAt if this is a new document + if (this.isNew && !doc.createdAt) { + doc.createdAt = now; + } + + next(); + }); + + // Middleware for update operations + const updateMethods = [ + "updateOne", + "updateMany", + "findOneAndUpdate", + "findByIdAndUpdate", + ] as const; + + for (const method of updateMethods) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + schema.pre(method as any, function (this: Query, next: (err?: Error) => void) { + const update = this.getUpdate(); + + // Increment __v and manage timestamps + if (update && typeof update === "object") { + // Handle both $set and direct updates + if ("$set" in update) { + (update.$set as Record).updatedAt = new Date(); + // Prevent createdAt from being overwritten + delete (update.$set as Record).createdAt; + // Remove __v from $set if present to avoid conflict with $inc + delete (update.$set as Record).__v; + } else if (!("$setOnInsert" in update)) { + (update as Record).updatedAt = new Date(); + // Prevent createdAt from being overwritten + delete (update as Record).createdAt; + } + + // Increment version - only if not using $set with __v + if ("$inc" in update) { + (update.$inc as Record).__v = + ((update.$inc as Record).__v || 0) + 1; + } else { + (update as Record).$inc = { __v: 1 }; + } + } + + next(); + }); + } + + // Add validation middleware for update operations + for (const method of updateMethods) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + schema.pre(method as any, function (this: Query, next: (err?: Error) => void) { + // Set runValidators to true to ensure validation runs on updates + this.setOptions({ runValidators: true }); + next(); + }); + } + + // Also ensure validation runs on update() method + // eslint-disable-next-line @typescript-eslint/no-explicit-any + schema.pre("update" as any, function (this: Query, next: (err?: Error) => void) { + this.setOptions({ runValidators: true }); + next(); + }); + + // Middleware for replaceOne + schema.pre("replaceOne", function (this: Query, next: (err?: Error) => void) { + const replacement = this.getUpdate(); + + if (replacement && typeof replacement === "object") { + (replacement as Record).updatedAt = new Date(); + // Don't overwrite createdAt + if (!this.getOptions().upsert) { + delete (replacement as Record).createdAt; + } + } + + next(); + }); + + // Middleware for insertMany - only set createdAt, not updatedAt + schema.pre("insertMany", function (next: (err?: Error) => void, docs: unknown[]) { + const now = new Date(); + for (const doc of docs) { + if (doc && typeof doc === "object") { + const docObj = doc as Record; + if (!docObj.createdAt) { + docObj.createdAt = now; + } + if (!docObj.updatedAt) { + docObj.updatedAt = now; + } + } + } + next(); + }); +} + +/** + * Legacy function that applies the standard middleware plugin to a schema + * @deprecated Use schema.plugin(standardMiddlewarePlugin) instead + * @param schema The mongoose schema to add middleware to + */ +export function applyStandardMiddleware(schema: Schema): void { + standardMiddlewarePlugin(schema); +} diff --git a/packages/mongoose/src/schema.ts b/packages/mongoose/src/schema.ts new file mode 100644 index 0000000000..12a46e5953 --- /dev/null +++ b/packages/mongoose/src/schema.ts @@ -0,0 +1,110 @@ +// Copyright 2021-2025 Prosopo (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { + Connection, + Model, + Schema, + SchemaDefinition, + SchemaOptions, +} from "mongoose"; +import { Schema as MongooseSchema } from "mongoose"; +import { standardMiddlewarePlugin } from "./middleware.js"; + +/** + * Creates a new mongoose schema with standard middleware plugin applied + * This is the recommended way to create schemas to ensure middleware is applied consistently + * @param definition Schema definition + * @param options Schema options (timestamps will be set to true if not explicitly provided) + * @returns Schema with middleware applied via plugin + */ +export function newSchema( + definition?: SchemaDefinition, + options?: SchemaOptions, + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): Schema { + // Merge options with timestamps enabled by default + const schemaOptions: SchemaOptions = { + ...options, + timestamps: options?.timestamps !== undefined ? options.timestamps : true, + }; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const schema = new MongooseSchema(definition as any, schemaOptions as any); + // Apply standard middleware via plugin + schema.plugin(standardMiddlewarePlugin); + return schema; +} + +/** + * Creates a mongoose schema with standard middleware applied + * @deprecated Use newSchema instead + * @param definition Schema definition + * @param options Schema options + * @returns Schema with middleware applied + */ +export function createSchemaWithMiddleware( + definition?: SchemaDefinition, + options?: SchemaOptions, + // eslint-disable-next-line @typescript-eslint/no-explicit-any +): Schema { + return newSchema(definition, options); +} + +/** + * Creates or retrieves a model on a connection + * Uses mongoose's overwriteModels setting to allow multiple .model() calls + * @param connection The mongoose connection + * @param modelName The name of the model + * @param schema The mongoose schema + * @returns The model + */ +export function getOrCreateModel( + connection: Connection, + modelName: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + schema: Schema, +): Model { + // Enable overwriteModels to allow redefining models without errors + connection.set("overwriteModels", true); + + // Simply call model - mongoose will handle caching/overwriting + return connection.model(modelName, schema); +} + +/** + * Creates a mongoose schema with standard middleware and returns a model creation function + * @param definition Schema definition + * @param options Schema options + * @returns Function to create models with the schema + */ +export function createSchemaBuilder( + definition?: SchemaDefinition, + options?: SchemaOptions, +) { + const schema = newSchema(definition, options); + + return { + schema, + /** + * Creates or retrieves a model on the specified connection + * @param connection The mongoose connection + * @param modelName The name of the model + * @returns The model + */ + createModel: (connection: Connection, modelName: string): Model => { + return getOrCreateModel(connection, modelName, schema); + }, + }; +} diff --git a/packages/mongoose/src/tests/mongoose.test.ts b/packages/mongoose/src/tests/mongoose.test.ts new file mode 100644 index 0000000000..ae701ff59c --- /dev/null +++ b/packages/mongoose/src/tests/mongoose.test.ts @@ -0,0 +1,300 @@ +// Copyright 2021-2025 Prosopo (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { MongoMemoryServer } from "mongodb-memory-server"; +import type { Connection } from "mongoose"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; +import { z } from "zod"; +import { + createModelFromZodSchema, + createMongooseConnection, + createSchemaBuilder, + createSchemaWithMiddleware, + getOrCreateModel, +} from "../index.js"; + +describe("Mongoose utilities", () => { + let mongoServer: MongoMemoryServer; + let connection: Connection; + + beforeAll(async () => { + mongoServer = await MongoMemoryServer.create(); + const uri = mongoServer.getUri(); + connection = await createMongooseConnection({ + url: uri, + dbname: "test", + }); + }); + + afterAll(async () => { + await connection.close(); + await mongoServer.stop(); + }); + + describe("createMongooseConnection", () => { + it("should create a connection to MongoDB", async () => { + expect(connection).toBeDefined(); + expect(connection.readyState).toBe(1); // 1 = connected + }); + }); + + describe("createSchemaWithMiddleware", () => { + it("should create a schema with timestamps", () => { + interface TestDoc { + name: string; + createdAt?: Date; + updatedAt?: Date; + } + + const schema = createSchemaWithMiddleware({ + name: { type: String, required: true }, + }); + + expect(schema.path("createdAt")).toBeDefined(); + expect(schema.path("updatedAt")).toBeDefined(); + }); + + it("should set createdAt and updatedAt on save", async () => { + interface TestDoc { + name: string; + createdAt?: Date; + updatedAt?: Date; + } + + const schema = createSchemaWithMiddleware({ + name: { type: String, required: true }, + }); + const Model = connection.model("TestSave", schema); + + const doc = new Model({ name: "test" }); + await doc.save(); + + const savedDoc = doc.toObject() as TestDoc; + expect(savedDoc.createdAt).toBeInstanceOf(Date); + expect(savedDoc.updatedAt).toBeInstanceOf(Date); + }); + + it("should update updatedAt on subsequent saves", async () => { + interface TestDoc { + name: string; + createdAt?: Date; + updatedAt?: Date; + } + + const schema = createSchemaWithMiddleware({ + name: { type: String, required: true }, + }); + const Model = connection.model("TestUpdate", schema); + + const doc = new Model({ name: "test" }); + await doc.save(); + + const savedDoc = doc.toObject() as TestDoc; + const originalCreatedAt = savedDoc.createdAt; + const originalUpdatedAt = savedDoc.updatedAt; + + // Wait a bit to ensure different timestamp + await new Promise((resolve) => setTimeout(resolve, 10)); + + doc.name = "updated"; + await doc.save(); + + const updatedDoc = doc.toObject() as TestDoc; + expect(updatedDoc.createdAt).toEqual(originalCreatedAt); + expect(updatedDoc.updatedAt?.getTime()).toBeGreaterThan( + originalUpdatedAt?.getTime() || 0, + ); + }); + + it("should increment __v on update operations", async () => { + interface TestDoc { + name: string; + createdAt?: Date; + updatedAt?: Date; + } + + const schema = createSchemaWithMiddleware({ + name: { type: String, required: true }, + }); + const Model = connection.model("TestVersion", schema); + + const doc = new Model({ name: "test" }); + await doc.save(); + + const originalVersion = doc.__v; + + await Model.updateOne({ _id: doc._id }, { name: "updated" }); + + const updated = await Model.findById(doc._id); + expect(updated?.__v).toBe((originalVersion || 0) + 1); + }); + + it("should not overwrite createdAt on updates", async () => { + interface TestDoc { + name: string; + createdAt?: Date; + updatedAt?: Date; + } + + const schema = createSchemaWithMiddleware({ + name: { type: String, required: true }, + }); + const Model = connection.model("TestCreatedAtProtection", schema); + + const doc = new Model({ name: "test" }); + await doc.save(); + + const savedDoc = doc.toObject() as TestDoc; + const originalCreatedAt = savedDoc.createdAt; + + await Model.updateOne( + { _id: doc._id }, + { name: "updated", createdAt: new Date() }, + ); + + const updated = await Model.findById(doc._id); + const updatedDoc = updated?.toObject() as TestDoc; + expect(updatedDoc?.createdAt).toEqual(originalCreatedAt); + }); + }); + + describe("getOrCreateModel", () => { + it("should return the same model instance when called multiple times", () => { + const schema = createSchemaWithMiddleware({ + name: { type: String, required: true }, + }); + + const Model1 = getOrCreateModel(connection, "CachedModel", schema); + const Model2 = getOrCreateModel(connection, "CachedModel", schema); + + expect(Model1).toBe(Model2); + }); + }); + + describe("createSchemaBuilder", () => { + it("should create a schema and model factory", () => { + const builder = createSchemaBuilder({ + name: { type: String, required: true }, + }); + + expect(builder.schema).toBeDefined(); + expect(builder.createModel).toBeDefined(); + + const Model = builder.createModel(connection, "BuiltModel"); + expect(Model).toBeDefined(); + }); + }); + + describe("createModelFromZodSchema", () => { + it("should create a model from a Zod schema", () => { + const zodSchema = z.object({ + name: z.string(), + age: z.number(), + }); + + const Model = createModelFromZodSchema( + connection, + "ZodModel", + zodSchema, + ); + expect(Model).toBeDefined(); + }); + + it("should validate data with Zod on save", async () => { + const zodSchema = z.object({ + name: z.string(), + age: z.number().min(0).max(120), + }); + + const Model = createModelFromZodSchema( + connection, + "ZodValidation", + zodSchema, + ); + + // Valid data should work + const validDoc = new Model({ name: "John", age: 30 }); + await expect(validDoc.save()).resolves.toBeDefined(); + + // Invalid data should fail + const invalidDoc = new Model({ name: "Jane", age: 150 }); + await expect(invalidDoc.save()).rejects.toThrow(); + }); + + it("should validate updates with Zod", async () => { + const zodSchema = z.object({ + name: z.string().min(1), + age: z.number(), + }); + + const Model = createModelFromZodSchema( + connection, + "ZodUpdateValidation", + zodSchema, + ); + + const doc = new Model({ name: "John", age: 30 }); + await doc.save(); + + // Invalid update should fail + await expect( + Model.updateOne({ _id: doc._id }, { name: "" }), + ).rejects.toThrow(); + }); + + it("should handle optional fields in Zod schema", async () => { + const zodSchema = z.object({ + name: z.string(), + email: z.string().email().optional(), + }); + + const Model = createModelFromZodSchema( + connection, + "ZodOptional", + zodSchema, + ); + + const doc1 = new Model({ name: "John" }); + await expect(doc1.save()).resolves.toBeDefined(); + + const doc2 = new Model({ name: "Jane", email: "jane@example.com" }); + await expect(doc2.save()).resolves.toBeDefined(); + }); + + it("should include timestamp fields from middleware", async () => { + interface TestDoc { + name: string; + createdAt?: Date; + updatedAt?: Date; + } + + const zodSchema = z.object({ + name: z.string(), + }); + + const Model = createModelFromZodSchema( + connection, + "ZodTimestamps", + zodSchema, + ); + + const doc = new Model({ name: "test" }); + await doc.save(); + + const savedDoc = doc.toObject() as TestDoc; + expect(savedDoc.createdAt).toBeInstanceOf(Date); + expect(savedDoc.updatedAt).toBeInstanceOf(Date); + }); + }); +}); diff --git a/packages/mongoose/src/zodMapper.ts b/packages/mongoose/src/zodMapper.ts new file mode 100644 index 0000000000..72230e4a93 --- /dev/null +++ b/packages/mongoose/src/zodMapper.ts @@ -0,0 +1,231 @@ +// Copyright 2021-2025 Prosopo (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import type { Connection, Model, Query, Schema, SchemaDefinition } from "mongoose"; +import { Schema as MongooseSchema } from "mongoose"; +import { z } from "zod"; +import { standardMiddlewarePlugin } from "./middleware.js"; +import { getOrCreateModel } from "./schema.js"; + +/** + * Converts a Zod schema to a Mongoose schema definition + * Note: This is a basic implementation that handles common types + * More complex types may need manual mapping + * @param zodSchema The Zod schema to convert + * @returns Mongoose schema definition + */ +export function zodToMongooseSchema( + zodSchema: z.ZodObject, +): SchemaDefinition { + const shape = zodSchema.shape; + const mongooseSchema: SchemaDefinition = {}; + + for (const [key, value] of Object.entries(shape)) { + mongooseSchema[key] = zodTypeToMongooseType( + value as z.ZodTypeAny, + ) as SchemaDefinition[string]; + } + + return mongooseSchema; +} + +/** + * Maps a Zod type to a Mongoose type + * @param zodType The Zod type + * @returns Mongoose type definition + */ +function zodTypeToMongooseType( + zodType: z.ZodTypeAny, +): Record { + // Handle optional and nullable types + if (zodType instanceof z.ZodOptional) { + const innerType = zodTypeToMongooseType(zodType.unwrap()); + return { + ...innerType, + required: false, + }; + } + + if (zodType instanceof z.ZodNullable) { + const innerType = zodTypeToMongooseType(zodType.unwrap()); + return { + ...innerType, + required: false, + }; + } + + if (zodType instanceof z.ZodDefault) { + const innerType = zodTypeToMongooseType(zodType.removeDefault()); + return { + ...innerType, + default: zodType._def.defaultValue(), + }; + } + + // Handle primitive types + if (zodType instanceof z.ZodString) { + return { type: String, required: true }; + } + + if (zodType instanceof z.ZodNumber) { + return { type: Number, required: true }; + } + + if (zodType instanceof z.ZodBoolean) { + return { type: Boolean, required: true }; + } + + if (zodType instanceof z.ZodDate) { + return { type: Date, required: true }; + } + + if (zodType instanceof z.ZodBigInt) { + // MongoDB doesn't natively support BigInt, use String + return { type: String, required: true }; + } + + // Handle arrays + if (zodType instanceof z.ZodArray) { + const elementType = zodTypeToMongooseType(zodType.element); + return { type: [elementType], required: true }; + } + + // Handle objects (nested schemas) + if (zodType instanceof z.ZodObject) { + return { type: zodToMongooseSchema(zodType), required: true }; + } + + // Handle enums + if (zodType instanceof z.ZodEnum) { + return { type: String, enum: zodType.options, required: true }; + } + + if (zodType instanceof z.ZodNativeEnum) { + return { type: String, enum: Object.values(zodType.enum), required: true }; + } + + // Handle unions (limited support - converts to Mixed) + if (zodType instanceof z.ZodUnion) { + return { type: Object, required: true }; + } + + // Handle any + if (zodType instanceof z.ZodAny) { + return { type: Object, required: true }; + } + + // Default to Mixed for unknown types + return { type: Object, required: true }; +} + +/** + * Creates a Mongoose model from a Zod schema with validation middleware + * @param connection The mongoose connection + * @param modelName The name of the model + * @param zodSchema The Zod schema + * @param mongooseSchema Optional pre-built mongoose schema (if you need custom mapping) + * @returns The model with Zod validation applied + */ +export function createModelFromZodSchema( + connection: Connection, + modelName: string, + zodSchema: z.ZodObject, + mongooseSchema?: Schema, +): Model> { + // Use provided schema or convert from Zod with timestamps enabled + const schema = + mongooseSchema || + new MongooseSchema(zodToMongooseSchema(zodSchema), { timestamps: true }); + + // Apply standard middleware via plugin (timestamps, version increment) + schema.plugin(standardMiddlewarePlugin); + + // Add pre-save validation using Zod + schema.pre("save", async function ( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this: any, + next: (err?: Error) => void, + ) { + try { + await zodSchema.parseAsync(this.toObject()); + next(); + } catch (err) { + if (err instanceof z.ZodError) { + next(new Error(`Validation failed: ${JSON.stringify(err.format())}`)); + } else { + next(err as Error); + } + } + }); + + // Add pre-validation for update operations + const updateMethods = [ + "updateOne", + "updateMany", + "findOneAndUpdate", + "findByIdAndUpdate", + ] as const; + + for (const method of updateMethods) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + schema.pre( + method as any, + async function ( + this: Query, + next: (err?: Error) => void, + ) { + try { + const update = this.getUpdate(); + if (update && typeof update === "object") { + // Extract the actual update data (handle $set, etc.) + const updateData = + "$set" in update + ? (update.$set as Record) + : (update as Record); + + // Partial validation for updates (allow optional fields) + const partialSchema = zodSchema.partial(); + await partialSchema.parseAsync(updateData); + } + next(); + } catch (err) { + if (err instanceof z.ZodError) { + next(new Error(`Update validation failed: ${JSON.stringify(err.format())}`)); + } else { + next(err as Error); + } + } + }, + ); + } + + // Add post-find validation (optional, can be expensive) + // Uncomment if you want to validate data coming out of the database + /* + schema.post(['find', 'findOne', 'findById'], async function(docs: unknown) { + if (!docs) return; + const docArray = Array.isArray(docs) ? docs : [docs]; + for (const doc of docArray) { + try { + await zodSchema.parseAsync(doc); + } catch (error) { + console.warn('Document validation failed:', error); + } + } + }); + */ + + // Use the model cache to allow multiple calls + return getOrCreateModel(connection, modelName, schema); +} diff --git a/packages/mongoose/tsconfig.cjs.json b/packages/mongoose/tsconfig.cjs.json new file mode 100644 index 0000000000..73bd46904c --- /dev/null +++ b/packages/mongoose/tsconfig.cjs.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.cjs.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": ["src", "src/**/*.json"], + "references": [ + { + "path": "../../dev/config/tsconfig.cjs.json" + } + ] +} diff --git a/packages/mongoose/tsconfig.json b/packages/mongoose/tsconfig.json new file mode 100644 index 0000000000..f5e764b56e --- /dev/null +++ b/packages/mongoose/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.esm.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./dist" + }, + "include": [ + "src", + "src/**/*.json", + "src/**/*.ts", + "src/**/*.tsx", + "src/**/*.d.ts" + ], + "references": [ + { + "path": "../../dev/config/tsconfig.json" + } + ] +} diff --git a/packages/mongoose/tsconfig.types.json b/packages/mongoose/tsconfig.types.json new file mode 100644 index 0000000000..e2d2929993 --- /dev/null +++ b/packages/mongoose/tsconfig.types.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": true, + "composite": false + } +} diff --git a/packages/mongoose/vite.cjs.config.ts b/packages/mongoose/vite.cjs.config.ts new file mode 100644 index 0000000000..5c2666dc75 --- /dev/null +++ b/packages/mongoose/vite.cjs.config.ts @@ -0,0 +1,22 @@ +import path from "node:path"; +// Copyright 2021-2025 Prosopo (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +import { ViteCommonJSConfig } from "@prosopo/config"; + +export default function () { + return ViteCommonJSConfig( + path.basename("."), + path.resolve("./tsconfig.json"), + ); +} diff --git a/packages/mongoose/vite.esm.config.ts b/packages/mongoose/vite.esm.config.ts new file mode 100644 index 0000000000..4444499bfa --- /dev/null +++ b/packages/mongoose/vite.esm.config.ts @@ -0,0 +1,20 @@ +// Copyright 2021-2025 Prosopo (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import path from "node:path"; +import { ViteEsmConfig } from "@prosopo/config"; + +export default function () { + return ViteEsmConfig(path.basename("."), path.resolve("./tsconfig.json")); +} diff --git a/packages/mongoose/vite.test.config.ts b/packages/mongoose/vite.test.config.ts new file mode 100644 index 0000000000..d6fda1d170 --- /dev/null +++ b/packages/mongoose/vite.test.config.ts @@ -0,0 +1,33 @@ +import fs from "node:fs"; +import path from "node:path"; +// Copyright 2021-2025 Prosopo (UK) Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +import { ViteTestConfig } from "@prosopo/config"; +import dotenv from "dotenv"; +process.env.NODE_ENV = "test"; +// if .env.test exists at this level, use it, otherwise use the one at the root +const envFile = `.env.${process.env.NODE_ENV || "development"}`; +let envPath = envFile; +if (fs.existsSync(envFile)) { + envPath = path.resolve(envFile); +} else if (fs.existsSync(`../../${envFile}`)) { + envPath = path.resolve(`../../${envFile}`); +} + +// Only load dotenv if file exists +if (envPath && fs.existsSync(envPath)) { + dotenv.config({ path: envPath }); +} + +export default ViteTestConfig(); diff --git a/packages/types-database/package.json b/packages/types-database/package.json index 269cf74e20..50227055bf 100644 --- a/packages/types-database/package.json +++ b/packages/types-database/package.json @@ -36,6 +36,7 @@ "dependencies": { "@prosopo/common": "3.1.23", "@prosopo/locale": "3.1.23", + "@prosopo/mongoose": "1.0.0", "@prosopo/types": "3.6.1", "@prosopo/user-access-policy": "3.5.29", "mongoose": "8.13.0", diff --git a/packages/types-database/src/types/captcha.ts b/packages/types-database/src/types/captcha.ts index 2344993810..328d0c8bac 100644 --- a/packages/types-database/src/types/captcha.ts +++ b/packages/types-database/src/types/captcha.ts @@ -14,6 +14,7 @@ import type { PoWCaptcha } from "@prosopo/types"; import { type RootFilterQuery, Schema } from "mongoose"; +import { newSchema } from "@prosopo/mongoose"; import type { IDatabase } from "./mongo.js"; import { type PoWCaptchaRecord, @@ -30,12 +31,12 @@ export type StoredSession = SessionRecord; export const StoredSessionRecordSchema: Schema = SessionRecordSchema; -export const StoredUserCommitmentRecordSchema: Schema = new Schema({ +export const StoredUserCommitmentRecordSchema: Schema = newSchema({ ...UserCommitmentRecordSchema.obj, }); StoredUserCommitmentRecordSchema.index({ sessionId: 1 }); -export const StoredPoWCaptchaRecordSchema: Schema = new Schema({ +export const StoredPoWCaptchaRecordSchema: Schema = newSchema({ ...PoWCaptchaRecordSchema.obj, }); StoredPoWCaptchaRecordSchema.index({ sessionId: 1 }); diff --git a/packages/types-database/src/types/client.ts b/packages/types-database/src/types/client.ts index 4bcdd2a601..b7edb47a79 100644 --- a/packages/types-database/src/types/client.ts +++ b/packages/types-database/src/types/client.ts @@ -28,6 +28,7 @@ import { } from "@prosopo/types"; import type mongoose from "mongoose"; import { Schema } from "mongoose"; +import { newSchema } from "@prosopo/mongoose"; import type { IDatabase } from "./mongo.js"; import type { ClientRecord, Tables } from "./provider.js"; @@ -160,7 +161,7 @@ type AccountRecord = mongoose.Document & { }; // Account format -export const AccountSchema = new Schema({ +export const AccountSchema = newSchema({ createdAt: Number, updatedAt: Number, signupEmail: String, diff --git a/packages/types-database/src/types/provider.ts b/packages/types-database/src/types/provider.ts index 87780a351c..0c078392d4 100644 --- a/packages/types-database/src/types/provider.ts +++ b/packages/types-database/src/types/provider.ts @@ -39,6 +39,7 @@ import { import type { AccessRulesStorage } from "@prosopo/user-access-policy"; import type mongoose from "mongoose"; import { type Document, type Model, type ObjectId, Schema } from "mongoose"; +import { newSchema } from "@prosopo/mongoose"; import { type ZodType, any, @@ -67,7 +68,7 @@ const ONE_WEEK = ONE_DAY * 7; const ONE_MONTH = ONE_WEEK * 4; const TEN_MINUTES = 10 * 60; -export const ClientRecordSchema = new Schema({ +export const ClientRecordSchema = newSchema({ account: String, settings: UserSettingsSchema, tier: { type: String, enum: Tier, required: true }, @@ -196,7 +197,7 @@ export type Tables = { [key in E]: typeof Model; }; -export const CaptchaRecordSchema = new Schema({ +export const CaptchaRecordSchema = newSchema({ captchaId: { type: String, required: true }, captchaContentId: { type: String, required: true }, assetURI: { type: String, required: false }, @@ -230,7 +231,7 @@ export type PoWCaptchaRecord = mongoose.Document & PoWCaptchaStored; export type UserCommitmentRecord = mongoose.Document & UserCommitment; -export const PoWCaptchaRecordSchema = new Schema({ +export const PoWCaptchaRecordSchema = newSchema({ challenge: { type: String, required: true }, dappAccount: { type: String, required: true }, userAccount: { type: String, required: true }, @@ -274,7 +275,7 @@ PoWCaptchaRecordSchema.index({ dappAccount: 1, requestedAtTimestamp: 1 }); PoWCaptchaRecordSchema.index({ "ipAddress.lower": 1 }); PoWCaptchaRecordSchema.index({ "ipAddress.upper": 1 }); -export const UserCommitmentRecordSchema = new Schema({ +export const UserCommitmentRecordSchema = newSchema({ userAccount: { type: String, required: true }, dappAccount: { type: String, required: true }, providerAccount: { type: String, required: true }, @@ -321,7 +322,7 @@ UserCommitmentRecordSchema.index({ userAccount: 1, dappAccount: 1 }); UserCommitmentRecordSchema.index({ "ipAddress.lower": 1 }); UserCommitmentRecordSchema.index({ "ipAddress.upper": 1 }); -export const DatasetRecordSchema = new Schema({ +export const DatasetRecordSchema = newSchema({ contentTree: { type: [[String]], required: true }, datasetContentId: { type: String, required: true }, datasetId: { type: String, required: true }, @@ -331,7 +332,7 @@ export const DatasetRecordSchema = new Schema({ // Set an index on the datasetId field, ascending DatasetRecordSchema.index({ datasetId: 1 }); -export const SolutionRecordSchema = new Schema({ +export const SolutionRecordSchema = newSchema({ captchaId: { type: String, required: true }, captchaContentId: { type: String, required: true }, datasetId: { type: String, required: true }, @@ -350,7 +351,7 @@ export const UserSolutionSchema = CaptchaSolutionSchema.extend({ }); export type UserSolutionRecord = mongoose.Document & zInfer; -export const UserSolutionRecordSchema = new Schema( +export const UserSolutionRecordSchema = newSchema( { captchaId: { type: String, required: true }, captchaContentId: { type: String, required: true }, @@ -378,7 +379,7 @@ export type UserCommitmentWithSolutions = zInfer< export type PendingCaptchaRequestMongoose = PendingCaptchaRequest; -export const PendingRecordSchema = new Schema({ +export const PendingRecordSchema = newSchema({ accountId: { type: String, required: true }, pending: { type: Boolean, required: true }, salt: { type: String, required: true }, @@ -412,7 +413,7 @@ export type ScheduledTaskRecord = mongoose.Document & ScheduledTask; type ScheduledTaskMongoose = ScheduledTaskRecord; -export const ScheduledTaskRecordSchema = new Schema({ +export const ScheduledTaskRecordSchema = newSchema({ processName: { type: String, enum: ScheduledTaskNames, required: true }, datetime: { type: Date, required: true, expires: ONE_WEEK }, updated: { type: Date, required: false }, @@ -466,7 +467,7 @@ export type Session = { export type SessionRecord = mongoose.Document & Session; -export const SessionRecordSchema = new Schema({ +export const SessionRecordSchema = newSchema({ sessionId: { type: String, required: true }, createdAt: { type: Date, required: true }, token: { type: String, required: true }, @@ -509,7 +510,7 @@ export type DetectorKey = { }; export type DetectorSchema = mongoose.Document & DetectorKey; -export const DetectorRecordSchema = new Schema({ +export const DetectorRecordSchema = newSchema({ createdAt: { type: Date, required: true }, detectorKey: { type: String, required: true }, expiresAt: { type: Date, required: false },