+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
- <component name="DataSourcePerFileMappings">
- <file url="mock:///model.js" value="1dddfa52-f936-4314-90df-4fcc802f6908" />
- <file url="mock:///model.js" value="1dddfa52-f936-4314-90df-4fcc802f6908" />
- <file url="mock:///model.js" value="1dddfa52-f936-4314-90df-4fcc802f6908" />
- </component>
-</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ai.zencoder.plugin.chat.index">
- <option name="activeChatId" value="744c3e10-33d2-414e-91ed-0472ce689be3" />
<option name="chatMetadata" value="{"744c3e10-33d2-414e-91ed-0472ce689be3":{"id":"744c3e10-33d2-414e-91ed-0472ce689be3","title":"Postgres Model Definitions Update","createdAt":1757523010531,"updatedAt":1757523030127,"isAgent":true,"isNameGenerated":true,"messageCount":3,"lastMessagePreview":"**Modifying model structure**\n\nI need to adjust user.model.js to align with the new schema and creat..."}}" />
</component>
</project>
\ No newline at end of file
"name": "phs-api",
"version": "1.0.0",
"dependencies": {
+ "bcrypt": "^5.0.1",
"body-parser": "^2.2.0",
"cookie-parser": "~1.4.4",
"cors": "^2.8.5",
"debug": "~2.6.9",
+ "dockerode": "^4.0.7",
"express": "5.0.0",
"express-compression": "^1.0.2",
"http-errors": "~1.6.3",
"node": ">=6.9.0"
}
},
+ "node_modules/@balena/dockerignore": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz",
+ "integrity": "sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q=="
+ },
"node_modules/@bcoe/v8-coverage": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
"tslib": "^2.4.0"
}
},
+ "node_modules/@grpc/grpc-js": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.13.4.tgz",
+ "integrity": "sha512-GsFaMXCkMqkKIvwCQjCrwH+GHbPKBjhwo/8ZuUkWHqbI73Kky9I+pQltrlT0+MWpedCoosda53lgjYfyEPgxBg==",
+ "dependencies": {
+ "@grpc/proto-loader": "^0.7.13",
+ "@js-sdsl/ordered-map": "^4.4.2"
+ },
+ "engines": {
+ "node": ">=12.10.0"
+ }
+ },
+ "node_modules/@grpc/proto-loader": {
+ "version": "0.7.15",
+ "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz",
+ "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==",
+ "dependencies": {
+ "lodash.camelcase": "^4.3.0",
+ "long": "^5.0.0",
+ "protobufjs": "^7.2.5",
+ "yargs": "^17.7.2"
+ },
+ "bin": {
+ "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@js-sdsl/ordered-map": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz",
+ "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/js-sdsl"
+ }
+ },
+ "node_modules/@mapbox/node-pre-gyp": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
+ "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==",
+ "dependencies": {
+ "detect-libc": "^2.0.0",
+ "https-proxy-agent": "^5.0.0",
+ "make-dir": "^3.1.0",
+ "node-fetch": "^2.6.7",
+ "nopt": "^5.0.0",
+ "npmlog": "^5.0.1",
+ "rimraf": "^3.0.2",
+ "semver": "^7.3.5",
+ "tar": "^6.1.11"
+ },
+ "bin": {
+ "node-pre-gyp": "bin/node-pre-gyp"
+ }
+ },
+ "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "dependencies": {
+ "semver": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@mapbox/node-pre-gyp/node_modules/semver": {
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/@napi-rs/wasm-runtime": {
"version": "0.2.12",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
"url": "https://opencollective.com/pkgr"
}
},
+ "node_modules/@protobufjs/aspromise": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+ "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
+ },
+ "node_modules/@protobufjs/base64": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+ "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
+ },
+ "node_modules/@protobufjs/codegen": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+ "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
+ },
+ "node_modules/@protobufjs/eventemitter": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+ "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
+ },
+ "node_modules/@protobufjs/fetch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+ "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
+ "dependencies": {
+ "@protobufjs/aspromise": "^1.1.1",
+ "@protobufjs/inquire": "^1.1.0"
+ }
+ },
+ "node_modules/@protobufjs/float": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+ "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
+ },
+ "node_modules/@protobufjs/inquire": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+ "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
+ },
+ "node_modules/@protobufjs/path": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+ "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
+ },
+ "node_modules/@protobufjs/pool": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+ "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
+ },
+ "node_modules/@protobufjs/utf8": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
+ },
"node_modules/@scarf/scarf": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz",
"version": "24.3.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz",
"integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==",
- "dev": true,
"dependencies": {
"undici-types": "~7.10.0"
}
"win32"
]
},
+ "node_modules/abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+ },
"node_modules/accepts": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
"node": ">=0.4.0"
}
},
+ "node_modules/agent-base": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+ "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "dependencies": {
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/agent-base/node_modules/debug": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/agent-base/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
"node_modules/ansi-escapes": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
},
+ "node_modules/aproba": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz",
+ "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew=="
+ },
+ "node_modules/are-we-there-yet": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz",
+ "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==",
+ "deprecated": "This package is no longer supported.",
+ "dependencies": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^3.6.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
},
"node_modules/basic-auth": {
"version": "2.0.1",
"node": ">= 0.8"
}
},
+ "node_modules/bcrypt": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz",
+ "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@mapbox/node-pre-gyp": "^1.0.11",
+ "node-addon-api": "^5.0.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
"node_modules/bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"tweetnacl": "^0.14.3"
}
},
+ "node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/bl/node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
"node_modules/body-parser": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
"node-int64": "^0.4.0"
}
},
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"is-regex": "^1.0.3"
}
},
+ "node_modules/chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/ci-info": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz",
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "dev": true,
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
"engines": {
"node": ">=8"
}
"node_modules/cliui/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/cliui/node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ },
+ "node_modules/color-support": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
+ "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
+ "bin": {
+ "color-support": "bin.js"
+ }
},
"node_modules/compressible": {
"version": "2.0.18",
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
"node_modules/concat-stream": {
"version": "2.0.0",
"typedarray": "^0.0.6"
}
},
+ "node_modules/console-control-strings": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+ "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="
+ },
"node_modules/constantinople": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz",
"node": ">=0.10.0"
}
},
+ "node_modules/delegates": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="
+ },
"node_modules/depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"node": ">= 0.6"
}
},
+ "node_modules/detect-libc": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
+ "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/detect-newline": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
"node": ">=8"
}
},
+ "node_modules/docker-modem": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-5.0.6.tgz",
+ "integrity": "sha512-ens7BiayssQz/uAxGzH8zGXCtiV24rRWXdjNha5V4zSOcxmAZsfGVm/PPFbwQdqEkDnhG+SyR9E3zSHUbOKXBQ==",
+ "dependencies": {
+ "debug": "^4.1.1",
+ "readable-stream": "^3.5.0",
+ "split-ca": "^1.0.1",
+ "ssh2": "^1.15.0"
+ },
+ "engines": {
+ "node": ">= 8.0"
+ }
+ },
+ "node_modules/docker-modem/node_modules/debug": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/docker-modem/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "node_modules/dockerode": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-4.0.8.tgz",
+ "integrity": "sha512-HdPBprWmwfHMHi12AVIFDhXIqIS+EpiOVkZaAZxgML4xf5McqEZjJZtahTPkLDxWOt84ApfWPAH9EoQwOiaAIQ==",
+ "dependencies": {
+ "@balena/dockerignore": "^1.0.2",
+ "@grpc/grpc-js": "^1.11.1",
+ "@grpc/proto-loader": "^0.7.13",
+ "docker-modem": "^5.0.6",
+ "protobufjs": "^7.3.2",
+ "tar-fs": "~2.1.3",
+ "uuid": "^10.0.0"
+ },
+ "engines": {
+ "node": ">= 8.0"
+ }
+ },
"node_modules/doctypes": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz",
"node": ">= 0.8"
}
},
+ "node_modules/end-of-stream": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
+ "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
"node_modules/error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
- "dev": true,
"engines": {
"node": ">=6"
}
"node": ">= 0.8"
}
},
+ "node_modules/fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
+ },
"node_modules/fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"node": ">=6 <7 || >=8"
}
},
+ "node_modules/fs-minipass": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+ "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/fs-minipass/node_modules/minipass": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+ "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fs-minipass/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
- "dev": true
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"node_modules/fsevents": {
"version": "2.3.3",
"darwin"
],
"engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/function-bind": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
- "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gauge": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
+ "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
+ "deprecated": "This package is no longer supported.",
+ "dependencies": {
+ "aproba": "^1.0.3 || ^2.0.0",
+ "color-support": "^1.1.2",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.1",
+ "object-assign": "^4.1.1",
+ "signal-exit": "^3.0.0",
+ "string-width": "^4.2.3",
+ "strip-ansi": "^6.0.1",
+ "wide-align": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/gauge/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/gauge/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ },
+ "node_modules/gauge/node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
+ },
+ "node_modules/gauge/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/gauge/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
}
},
"node_modules/gensync": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true,
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/has-unicode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+ "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="
+ },
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"node": ">= 0.6"
}
},
+ "node_modules/https-proxy-agent": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+ "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+ "dependencies": {
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/https-proxy-agent/node_modules/debug": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/https-proxy-agent/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
"node_modules/human-signals": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
"node": ">=0.10.0"
}
},
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
"node_modules/import-local": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
- "dev": true,
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true,
"engines": {
"node": ">=8"
}
"node": ">=8"
}
},
+ "node_modules/lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
+ },
"node_modules/lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
+ "node_modules/long": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
+ "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="
+ },
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"node": ">=16 || 14 >=14.17"
}
},
+ "node_modules/minizlib": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+ "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+ "dependencies": {
+ "minipass": "^3.0.0",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/minizlib/node_modules/minipass": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+ "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minizlib/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ },
"node_modules/mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"mkdirp": "bin/cmd.js"
}
},
+ "node_modules/mkdirp-classic": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
+ },
"node_modules/morgan": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz",
"node": ">= 0.6"
}
},
+ "node_modules/node-addon-api": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz",
+ "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA=="
+ },
+ "node_modules/node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
"node_modules/node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
"dev": true
},
+ "node_modules/nopt": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+ "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
+ "dependencies": {
+ "abbrev": "1"
+ },
+ "bin": {
+ "nopt": "bin/nopt.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"node": ">=8"
}
},
+ "node_modules/npmlog": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
+ "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==",
+ "deprecated": "This package is no longer supported.",
+ "dependencies": {
+ "are-we-there-yet": "^2.0.0",
+ "console-control-strings": "^1.1.0",
+ "gauge": "^3.0.0",
+ "set-blocking": "^2.0.0"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
"asap": "~2.0.3"
}
},
+ "node_modules/protobufjs": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz",
+ "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@protobufjs/aspromise": "^1.1.2",
+ "@protobufjs/base64": "^1.1.2",
+ "@protobufjs/codegen": "^2.0.4",
+ "@protobufjs/eventemitter": "^1.1.0",
+ "@protobufjs/fetch": "^1.1.0",
+ "@protobufjs/float": "^1.0.2",
+ "@protobufjs/inquire": "^1.1.0",
+ "@protobufjs/path": "^1.1.2",
+ "@protobufjs/pool": "^1.1.0",
+ "@protobufjs/utf8": "^1.1.0",
+ "@types/node": ">=13.7.0",
+ "long": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
"resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz",
"integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ=="
},
+ "node_modules/pump": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
+ "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
"node_modules/pure-rand": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="
},
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rimraf/node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/rimraf/node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rimraf/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/router": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
"node": ">= 18"
}
},
+ "node_modules/set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
+ },
"node_modules/setprototypeof": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
"node": ">=14.0.0"
}
},
+ "node_modules/split-ca": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz",
+ "integrity": "sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ=="
+ },
"node_modules/split2": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
"url": "https://opencollective.com/synckit"
}
},
+ "node_modules/tar": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
+ "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
+ "dependencies": {
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "minipass": "^5.0.0",
+ "minizlib": "^2.1.1",
+ "mkdirp": "^1.0.3",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/tar-fs": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz",
+ "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==",
+ "dependencies": {
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.1.4"
+ }
+ },
+ "node_modules/tar-fs/node_modules/chownr": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
+ },
+ "node_modules/tar-stream": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+ "dependencies": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tar/node_modules/minipass": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
+ "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/tar/node_modules/mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/tar/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ },
"node_modules/test-exclude": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
"resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz",
"integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg=="
},
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"node_modules/undici-types": {
"version": "7.10.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
- "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
- "dev": true
+ "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="
},
"node_modules/universalify": {
"version": "0.1.2",
"node": ">= 0.4.0"
}
},
+ "node_modules/uuid": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
+ "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/v8-to-istanbul": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
"makeerror": "1.0.12"
}
},
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"node": ">= 8"
}
},
+ "node_modules/wide-align": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
+ "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
+ "dependencies": {
+ "string-width": "^1.0.2 || 2 || 3 || 4"
+ }
+ },
+ "node_modules/wide-align/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wide-align/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ },
+ "node_modules/wide-align/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wide-align/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/with": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz",
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true,
"engines": {
"node": ">=10"
}
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
- "dev": true,
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "dev": true,
"engines": {
"node": ">=12"
}
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
"engines": {
"node": ">=8"
}
"node_modules/yargs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"node_modules/yargs/node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
"start-debug": "NODE_ENV=\"DEVELOPMENT\" nodemon --trace-warnings --inspect=0.0.0.0:9229 app.js"
},
"dependencies": {
+ "bcrypt": "^5.0.1",
"body-parser": "^2.2.0",
"cookie-parser": "~1.4.4",
"cors": "^2.8.5",
+/**
+ * @file Authentication controller for handling authentication requests
+ */
+
+const db = require('../models');
+const createError = require('http-errors');
+
+const updateUserAndReturn = async (validUser, res) => {
+ const token = await validUser.createToken();
+ res.status(200).send({ success: true, user: validUser.to_safe_json(), token });
+};
+
module.exports = {
- login: (req, res, next) => {
- console.log('login');
+ create: async (req, res, next) => {
+ const { user_id, password, password_confirmation } = req.body;
+ if (!user_id || !password || !password_confirmation || password !== password_confirmation) {
+ return next(createError(400, 'Invalid parameters: user_id, password, and password_confirmation are required and passwords must match.'));
+ }
+ try {
+ const user = await db.user.find_one({ id: user_id });
+ if (!user) {
+ return next(createError(400, 'There is no user with this id.'));
+ }
+ const existing = await db.authentication.find_by_user_id(user_id);
+ if (existing) {
+ return next(createError(400, 'Authentication for this user already exists.'));
+ }
+ await user.hashPassword(password);
+ const auth = await db.authentication.find_by_user_id(user_id);
+ res.status(200).send(auth.to_safe_json());
+ } catch (e) {
+ logger.error(`Create auth error: ${e.message}`);
+ next(e);
+ }
+ },
+
+ update: async (req, res, next) => {
+ try {
+ const auth = await db.authentication.find_one(req.params);
+ if (!auth) return next(createError(404, 'Authentication record not found'));
+ const updated = await auth.update(req.body);
+ res.status(200).send(updated.to_safe_json());
+ } catch (e) {
+ logger.error(`Update auth error: ${e.message}`);
+ next(createError(400, 'Invalid parameters.'));
+ }
+ },
+
+ show: async (req, res, next) => {
+ try {
+ const auth = await db.authentication.find_one(req.params);
+ if (!auth) return next(createError(404, 'Authentication record not found'));
+ res.status(200).send(auth.to_safe_json());
+ } catch (e) {
+ logger.error(`Show auth error: ${e.message}`);
+ next(e);
+ }
+ },
+
+ index: async (req, res, next) => {
+ try {
+ const auths = await db.authentication.find_many(req.query);
+ if (!auths.length) return next(createError(404, 'No authentication records found'));
+ res.status(200).send(auths.map(a => a.to_safe_json()));
+ } catch (e) {
+ logger.error(`Index auth error: ${e.message}`);
+ next(e);
+ }
+ },
+
+ authenticate: async (req, res, next) => {
+ try {
+ const { email, password } = req.body;
+ if (!email || !password) {
+ return next(createError(400, !email ? 'You must provide an email to login.' : 'You must provide a password to login.'));
+ }
+ const user = await db.user.find_by_email(email);
+ if (!user || !user.is_active || user.is_deleted) {
+ return res.status(401).send({ success: false, user: null, token: null });
+ }
+ const auth = await db.authentication.find_by_user_id(user.id);
+ if (auth.is_locked) {
+ return res.status(401).send({ message: 'Your account is locked due to suspicious activity. Please contact us to continue.' });
+ }
+ const isValid = await user.comparePassword(password);
+ if (!isValid) {
+ await user.failLogin();
+ return res.status(401).send({ success: false, user: null, token: null });
+ }
+ return updateUserAndReturn(user, res);
+ } catch (e) {
+ logger.error(`Authenticate error: ${e.message}`);
+ next(e);
+ }
},
};
\ No newline at end of file
--- /dev/null
+/**
+ * @file Media controller for handling media-related API requests
+ */
+
+const db = require('../models');
+const createError = require('http-errors');
+
+/**
+ * Media controller
+ * @type {Object}
+ */
+module.exports = {
+ /**
+ * Create a new media
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async create(req, res, next) {
+ try {
+ const media_data = req.body;
+ const media = await db.media.create(media_data);
+ res.json(media);
+ } catch (error) {
+ logger.error(`Create media error: ${error.message}`);
+ next(createError(error.status || 409, error.message));
+ }
+ },
+
+ /**
+ * Find media by file path
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async find_by_file_path(req, res, next) {
+ try {
+ const { file_path } = req.params;
+ const media = await db.media.find_by_file_path(file_path);
+ if (!media) return next(createError(404, 'Media not found'));
+ res.json(media);
+ } catch (error) {
+ logger.error(`Find media by file path error: ${error.message}`);
+ next(createError(error.status || 500, error.message));
+ }
+ },
+
+ /**
+ * Find one media by ID
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async find_one(req, res, next) {
+ try {
+ const { id } = req.params;
+ const media = await db.media.find_one({ id: parseInt(id) });
+ if (!media) return next(createError(404, 'Media not found'));
+ res.json(media);
+ } catch (error) {
+ logger.error(`Find media error: ${error.message}`);
+ next(createError(error.status || 500, error.message));
+ }
+ },
+
+ /**
+ * Find many media
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async find_many(req, res, next) {
+ try {
+ const { limit = '100', offset = '0', ...where } = req.query;
+ const medias = await db.media.find_many(where, [], null, parseInt(limit), parseInt(offset));
+ res.json(medias);
+ } catch (error) {
+ logger.error(`Find many media error: ${error.message}`);
+ next(createError(error.status || 500, error.message));
+ }
+ },
+
+ /**
+ * Update a media
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async update(req, res, next) {
+ try {
+ const { id } = req.params;
+ const media_data = req.body;
+ const media = await db.media.instance().find_one({ id: parseInt(id) });
+ if (!media) return next(createError(404, 'Media not found'));
+ const updated_media = await media.update(media_data);
+ res.json(updated_media);
+ } catch (error) {
+ logger.error(`Update media error: ${error.message}`);
+ next(createError(error.status || 400, error.message));
+ }
+ },
+
+ /**
+ * Soft delete a media
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async soft_delete(req, res, next) {
+ try {
+ const { id } = req.params;
+ const { deleted_by_id } = req.body;
+ const media = await db.media.instance().find_one({ id: parseInt(id) });
+ if (!media) return next(createError(404, 'Media not found'));
+ const deleted_media = await media.soft_delete(deleted_by_id);
+ res.json(deleted_media);
+ } catch (error) {
+ logger.error(`Soft delete media error: ${error.message}`);
+ next(createError(error.status || 400, error.message));
+ }
+ }
+};
\ No newline at end of file
--- /dev/null
+/**
+ * @file Message controller for handling message-related API requests
+ */
+
+const db = require('../models');
+const createError = require('http-errors');
+const logger = global.logger;
+
+/**
+ * Message controller
+ * @type {Object}
+ */
+module.exports = {
+ /**
+ * Create a new message
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async create(req, res, next) {
+ try {
+ const message_data = req.body;
+ const message = await db.message.create(message_data);
+ res.json(message);
+ } catch (error) {
+ logger.error(`Create message error: ${error.message}`);
+ next(createError(error.status || 409, error.message));
+ }
+ },
+
+ /**
+ * Find messages by group ID
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async find_by_group_id(req, res, next) {
+ try {
+ const { group_id } = req.params;
+ const { limit = 100, offset = 0 } = req.query;
+ const messages = await db.message.find_by_group_id(parseInt(group_id), [], null, parseInt(limit), parseInt(offset));
+ res.json(messages);
+ } catch (error) {
+ logger.error(`Find messages by group ID error: ${error.message}`);
+ next(createError(error.status || 500, error.message));
+ }
+ },
+
+ /**
+ * Find messages by recipient ID
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async find_by_recipient_id(req, res, next) {
+ try {
+ const { recipient_id } = req.params;
+ const { limit = 100, offset = 0 } = req.query;
+ const messages = await db.message.find_by_recipient_id(parseInt(recipient_id), [], null, parseInt(limit), parseInt(offset));
+ res.json(messages);
+ } catch (error) {
+ logger.error(`Find messages by recipient ID error: ${error.message}`);
+ next(createError(error.status || 500, error.message));
+ }
+ },
+
+ /**
+ * Find one message by ID
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async find_one(req, res, next) {
+ try {
+ const { id } = req.params;
+ const message = await db.message.find_one({ id: parseInt(id) });
+ if (!message) return next(createError(404, 'Message not found'));
+ res.json(message);
+ }
+ catch (error) {
+ logger.error(`Find message error: ${error.message}`);
+ next(createError(error.status || 500, error.message));
+ }
+ },
+
+ /**
+ * Find many messages
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async find_many(req, res, next) {
+ try {
+ const { limit = 100, offset = 0, ...where } = req.query;
+ const messages = await db.message.find_many(where, [], null, parseInt(limit), parseInt(offset));
+ res.json(messages);
+ } catch (error) {
+ logger.error(`Find many messages error: ${error.message}`);
+ next(createError(error.status || 500, error.message));
+ }
+ },
+
+ /**
+ * Mark a message as read
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async mark_as_read(req, res, next) {
+ try {
+ const { id } = req.params;
+ const message = await db.message.instance().find_one({ id: parseInt(id) });
+ if (!message) return next(createError(404, 'Message not found'));
+ const updated_message = await message.mark_as_read();
+ res.json(updated_message);
+ } catch (error) {
+ logger.error(`Mark message as read error: ${error.message}`);
+ next(createError(error.status || 400, error.message));
+ }
+ }
+};
\ No newline at end of file
--- /dev/null
+/**
+ * @file Message group controller for handling message group-related API requests
+ */
+
+const db = require('../models');
+const createError = require('http-errors');
+const logger = global.logger;
+
+/**
+ * Message group controller
+ * @type {Object}
+ */
+module.exports = {
+ /**
+ * Create a new message group
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async create(req, res, next) {
+ try {
+ const message_group_data = req.body;
+ const message_group = await db.message_group.create(message_group_data);
+ res.json(message_group);
+ } catch (error) {
+ logger.error(`Create message group error: ${error.message}`);
+ next(createError(error.status || 409, error.message));
+ }
+ },
+
+ /**
+ * Find one message group by ID
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async find_one(req, res, next) {
+ try {
+ const { id } = req.params;
+ const message_group = await db.message_group.find_one({ id: parseInt(id) });
+ if (!message_group) return next(createError(404, 'Message group not found'));
+ res.json(message_group);
+ } catch (error) {
+ logger.error(`Find message group error: ${error.message}`);
+ next(createError(error.status || 500, error.message));
+ }
+ },
+
+ /**
+ * Find many message groups
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async find_many(req, res, next) {
+ try {
+ const { limit = 100, offset = 0, ...where } = req.query;
+ const message_groups = await db.message_group.find_many(where, [], null, parseInt(limit), parseInt(offset));
+ res.json(message_groups);
+ } catch (error) {
+ logger.error(`Find many message groups error: ${error.message}`);
+ next(createError(error.status || 500, error.message));
+ }
+ },
+
+ /**
+ * Update a message group
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async update(req, res, next) {
+ try {
+ const { id } = req.params;
+ const message_group_data = req.body;
+ const message_group = await db.message_group.instance().find_one({ id: parseInt(id) });
+ if (!message_group) return next(createError(404, 'Message group not found'));
+ const updated_message_group = await message_group.update(message_group_data);
+ res.json(updated_message_group);
+ } catch (error) {
+ logger.error(`Update message group error: ${error.message}`);
+ next(createError(error.status || 400, error.message));
+ }
+ }
+};
\ No newline at end of file
--- /dev/null
+/**
+ * @file Message group members controller for handling message group member-related API requests
+ */
+
+const db = require('../models');
+const createError = require('http-errors');
+const logger = global.logger;
+
+/**
+ * Message group members controller
+ * @type {Object}
+ */
+module.exports = {
+ /**
+ * Add a message group member relation
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async add_relation(req, res, next) {
+ try {
+ const { group_id, user_id } = req.body;
+ const relation = await db.message_group_members.add_relation(group_id, user_id);
+ res.json(relation);
+ } catch (error) {
+ logger.error(`Add message group member relation error: ${error.message}`);
+ next(createError(error.status || 409, error.message));
+ }
+ },
+
+ /**
+ * Remove a message group member relation
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async remove_relation(req, res, next) {
+ try {
+ const { user_id, group_id } = req.body;
+ const relation = await db.message_group_members.remove_relation(user_id, group_id);
+ if (!relation) return next(createError(404, 'Relation not found'));
+ res.json(relation);
+ } catch (error) {
+ logger.error(`Remove message group member relation error: ${error.message}`);
+ next(createError(error.status || 400, error.message));
+ }
+ },
+
+ /**
+ * Find message group member relation by IDs
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async find_by_ids(req, res, next) {
+ try {
+ const { group_id, user_id } = req.params;
+ const relation = await db.message_group_members.find_by_ids(parseInt(group_id), parseInt(user_id));
+ if (!relation) return next(createError(404, 'Relation not found'));
+ res.json(relation);
+ } catch (error) {
+ logger.error(`Find message group member by IDs error: ${error.message}`);
+ next(createError(error.status || 500, error.message));
+ }
+ },
+
+ /**
+ * Find message group member relations by group ID
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async find_by_group_id(req, res, next) {
+ try {
+ const { group_id } = req.params;
+ const { limit = 100, offset = 0 } = req.query;
+ const relations = await db.message_group_members.find_by_group_id(parseInt(group_id), [], null, parseInt(limit), parseInt(offset));
+ res.json(relations);
+ } catch (error) {
+ logger.error(`Find message group members by group ID error: ${error.message}`);
+ next(createError(error.status || 500, error.message));
+ }
+ }
+};
\ No newline at end of file
--- /dev/null
+/**
+ * @file Post controller for handling post-related API requests
+ */
+
+const db = require('../models');
+const createError = require('http-errors');
+const logger = global.logger;
+
+/**
+ * Post controller
+ * @type {Object}
+ */
+module.exports = {
+ /**
+ * Create a new post
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async create(req, res, next) {
+ try {
+ const post_data = req.body;
+ const post = await db.post.create(post_data);
+ res.json(post);
+ } catch (error) {
+ logger.error(`Create post error: ${error.message}`);
+ next(createError(error.status || 409, error.message));
+ }
+ },
+
+ /**
+ * Find post by title
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async find_by_title(req, res, next) {
+ try {
+ const { title } = req.params;
+ const post = await db.post.find_by_title(title);
+ if (!post) return next(createError(404, 'Post not found'));
+ res.json(post);
+ } catch (error) {
+ logger.error(`Find post by title error: ${error.message}`);
+ next(createError(error.status || 500, error.message));
+ }
+ },
+
+ /**
+ * Find one post by ID
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async find_one(req, res, next) {
+ try {
+ const { id } = req.params;
+ const post = await db.post.find_one({ id: parseInt(id) });
+ if (!post) return next(createError(404, 'Post not found'));
+ res.json(post);
+ } catch (error) {
+ logger.error(`Find post error: ${error.message}`);
+ next(createError(error.status || 500, error.message));
+ }
+ },
+
+ /**
+ * Find many posts
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async find_many(req, res, next) {
+ try {
+ const { limit = 100, offset = 0, ...where } = req.query;
+ const posts = await db.post.find_many(where, [], null, parseInt(limit), parseInt(offset));
+ res.json(posts);
+ } catch (error) {
+ logger.error(`Find many posts error: ${error.message}`);
+ next(createError(error.status || 500, error.message));
+ }
+ },
+
+ /**
+ * Update a post
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async update(req, res, next) {
+ try {
+ const { id } = req.params;
+ const post_data = req.body;
+ const post = await db.post.instance().find_one({ id: parseInt(id) });
+ if (!post) return next(createError(404, 'Post not found'));
+ const updated_post = await post.update(post_data);
+ res.json(updated_post);
+ } catch (error) {
+ logger.error(`Update post error: ${error.message}`);
+ next(createError(error.status || 400, error.message));
+ }
+ },
+
+ /**
+ * Soft delete a post
+ * @param {Object} req - Express request object
+ * @param {Object} res - Express response object
+ * @param {Function} next - Express next middleware function
+ * @returns {Promise<void>}
+ */
+ async soft_delete(req, res, next) {
+ try {
+ const { id } = req.params;
+ const { deleted_by_id } = req.body;
+ const post = await db.post.instance().find_one({ id: parseInt(id) });
+ if (!post) return next(createError(404, 'Post not found'));
+ const deleted_post = await post.soft_delete(deleted_by_id);
+ res.json(deleted_post);
+ } catch (error) {
+ logger.error(`Soft delete post error: ${error.message}`);
+ next(createError(error.status || 400, error.message));
+ }
+ }
+};
\ No newline at end of file
return checkKey;
};
-module.exports = { validateAuth, allowApi };
\ No newline at end of file
+const restrictToRoles = (roles) => (req, res, next) => {
+ if (!req.user || !req.user.roles.some(r => roles.includes(r))) {
+ return next(createError(403, 'Forbidden: Insufficient role permissions'));
+ }
+ next();
+};
+
+module.exports = { validateAuth, allowApi, restrictToRoles };
\ No newline at end of file
*/
const model_cache = new Map();
-const { NotFoundError, FailedToCreateError, ValidationError } = require( './model' );
+const { NotFoundError } = require( './model' );
/**
* Get a model class from cache or require it
* @param {string} name - Model name
* @returns {Function} Model class
*/
-const get_model = ( name ) => {
- if (!model_cache.has( name )) {
- model_cache.set( name, require( `./${ name }.model` ) );
+const get_model = (name) => {
+ if (!model_cache.has(name)) {
+ model_cache.set(name, require(`./${name}.model`));
}
- return model_cache.get( name );
+ return model_cache.get(name);
};
/**
* @returns {Function} User model class
*/
-const get_user_model = () => get_model( 'user' );
+const get_user_model = () => get_model('user');
/**
* @returns {Function} Phone number model class
*/
-const get_phone_number_model = () => get_model( 'phone_number' );
+const get_phone_number_model = () => get_model('phone_number');
/**
* @returns {Function} User phone numbers model class
*/
-const get_user_phone_numbers_model = () => get_model( 'user_phone_numbers' );
+const get_user_phone_numbers_model = () => get_model('user_phone_numbers');
/**
* @returns {Function} Address model class
*/
-const get_address_model = () => get_model( 'address' );
+const get_address_model = () => get_model('address');
/**
* @returns {Function} User addresses model class
*/
-const get_user_addresses_model = () => get_model( 'user_addresses' );
+const get_user_addresses_model = () => get_model('user_addresses');
/**
* @returns {Function} Authentication model class
*/
-const get_authentication_model = () => get_model( 'authentication' );
+const get_authentication_model = () => get_model('authentication');
/**
* @returns {Function} Role model class
*/
-const get_role_model = () => get_model( 'role' );
+const get_role_model = () => get_model('role');
/**
* @returns {Function} User roles model class
*/
-const get_user_roles_model = () => get_model( 'user_roles' );
+const get_user_roles_model = () => get_model('user_roles');
+
+/**
+ * @returns {Function} Media model class
+ */
+const get_media_model = () => get_model('media');
+
+/**
+ * @returns {Function} Post model class
+ */
+const get_post_model = () => get_model('post');
+
+/**
+ * @returns {Function} Message group model class
+ */
+const get_message_group_model = () => get_model('message_group');
+
+/**
+ * @returns {Function} Message group members model class
+ */
+const get_message_group_members_model = () => get_model('message_group_members');
+
+/**
+ * @returns {Function} Message model class
+ */
+const get_message_model = () => get_model('message');
/**
* Unified database interface
* @type {Object}
*/
const db = {
- user:{
- /**
- * Create a new user
- * @param {Object} user_data - User data
- * @returns {Promise<User>} Created user instance
- * @throws {ValidationError} If required fields are missing
- * @throws {FailedToCreateError} If creation fails
- */
- async create( user_data ) {
+ user: {
+ async create(user_data) {
try {
- return await get_user_model().create( user_data );
+ return await get_user_model().create(user_data);
} catch (error) {
- logger.error( `Failed to create user: ${ error.message }` );
+ logger.error(`Failed to create user: ${error.message}`);
throw error;
}
},
- /**
- * Find user by email
- * @param {string} email - Email to search for
- * @param {string[]} [excludes] - Fields to exclude
- * @returns {Promise<User|null>} User instance or null
- */
- async find_by_email( email, excludes ) {
+ async find_by_email(email, excludes) {
try {
- return await get_user_model().find_by_email( email, excludes );
+ return await get_user_model().find_by_email(email, excludes);
} catch (error) {
- logger.error( `Failed to find user by email: ${ error.message }` );
+ logger.error(`Failed to find user by email: ${error.message}`);
throw error;
}
},
- /**
- * Find user by nickname
- * @param {string} nickname - Nickname to search for
- * @param {string[]} [excludes] - Fields to exclude
- * @returns {Promise<User|null>} User instance or null
- */
- async find_by_nickname( nickname, excludes ) {
+ async find_by_nickname(nickname, excludes) {
try {
- return await get_user_model().find_by_nickname( nickname, excludes );
+ return await get_user_model().find_by_nickname(nickname, excludes);
} catch (error) {
- logger.error( `Failed to find user by nickname: ${ error.message }` );
+ logger.error(`Failed to find user by nickname: ${error.message}`);
throw error;
}
},
- /**
- * Find active users
- * @param {string[]} [excludes] - Fields to exclude
- * @param {{name: string, direction?: 'asc'|'desc'}||null} [order_by] - Order by configuration
- * @param {number} [limit] - Maximum number of records
- * @param {number} [offset] - Number of records to skip
- * @returns {Promise<User[]>} Array of active users
- */
- async find_active( excludes, order_by, limit, offset ) {
+ async find_active(excludes, order_by, limit, offset) {
try {
- return await get_user_model().find_active( excludes, order_by, limit, offset );
+ return await get_user_model().find_active(excludes, order_by, limit, offset);
} catch (error) {
- logger.error( `Failed to find active users: ${ error.message }` );
+ logger.error(`Failed to find active users: ${error.message}`);
throw error;
}
},
- /**
- * Find deleted users
- * @param {string[]} [excludes] - Fields to exclude
- * @param {{name: string, direction?: 'asc'|'desc'}||null} [order_by] - Order by configuration
- * @param {number} [limit] - Maximum number of records
- * @param {number} [offset] - Number of records to skip
- * @returns {Promise<User[]>} Array of deleted users
- */
- async find_deleted( excludes, order_by, limit, offset ) {
+ async find_deleted(excludes, order_by, limit, offset) {
try {
- return await get_user_model().find_deleted( excludes, order_by, limit, offset );
+ return await get_user_model().find_deleted(excludes, order_by, limit, offset);
} catch (error) {
- logger.error( `Failed to find deleted users: ${ error.message }` );
+ logger.error(`Failed to find deleted users: ${error.message}`);
throw error;
}
},
- /**
- * Find one user
- * @param {Object} where - Conditions
- * @param {string[]} [excludes] - Fields to exclude
- * @returns {Promise<User|null>} User instance or null
- */
- async find_one( where, excludes ) {
+ async find_one(where, excludes) {
try {
- return await new (get_user_model())().find_one( where, excludes );
+ return await new (get_user_model())().find_one(where, excludes);
} catch (error) {
- logger.error( `Failed to find one user: ${ error.message }` );
+ logger.error(`Failed to find one user: ${error.message}`);
throw error;
}
},
- /**
- * Find many users
- * @param {Object} [where] - Conditions
- * @param {string[]} [excludes] - Fields to exclude
- * @param {{name: string, direction?: 'asc'|'desc'}||null} [order_by] - Order by configuration
- * @param {number} [limit] - Maximum number of records
- * @param {number} [offset] - Number of records to skip
- * @returns {Promise<User[]>} Array of users
- */
- async find_many( where, excludes, order_by, limit, offset ) {
+ async find_many(where, excludes, order_by, limit, offset) {
try {
- return await new (get_user_model())().find_many( where, excludes, order_by, limit, offset );
+ return await new (get_user_model())().find_many(where, excludes, order_by, limit, offset);
} catch (error) {
- logger.error( `Failed to find many users: ${ error.message }` );
+ logger.error(`Failed to find many users: ${error.message}`);
throw error;
}
},
- /**
- * Deactivate user
- * @param {number|string} id - User ID
- * @param {number|string} deactivated_by_id - ID of user performing deactivation
- * @returns {Promise<User>} Updated user instance
- * @throws {NotFoundError} If user not found
- */
- async deactivate( id, deactivated_by_id ) {
+ async deactivate(id, deactivated_by_id) {
try {
- const user = await new (get_user_model())().find_one( { id }, [] );
- if (!user) throw new NotFoundError( 'User not found' );
- return await user.deactivate( deactivated_by_id );
+ const user = await new (get_user_model())().find_one({ id }, []);
+ if (!user) throw new NotFoundError('User not found');
+ return await user.deactivate(deactivated_by_id);
} catch (error) {
- logger.error( `Failed to deactivate user: ${ error.message }` );
+ logger.error(`Failed to deactivate user: ${error.message}`);
throw error;
}
},
- /**
- * Reactivate user
- * @param {number|string} id - User ID
- * @returns {Promise<User>} Updated user instance
- * @throws {NotFoundError} If user not found
- */
- async reactivate( id ) {
+ async reactivate(id) {
try {
- const user = await new (get_user_model())().find_one( { id }, [] );
- if (!user) throw new NotFoundError( 'User not found' );
+ const user = await new (get_user_model())().find_one({ id }, []);
+ if (!user) throw new NotFoundError('User not found');
return await user.reactivate();
} catch (error) {
- logger.error( `Failed to reactivate user: ${ error.message }` );
+ logger.error(`Failed to reactivate user: ${error.message}`);
throw error;
}
},
- /**
- * Soft delete user
- * @param {number|string} id - User ID
- * @param {number|string} deleted_by_id - ID of user performing deletion
- * @returns {Promise<User>} Updated user instance
- * @throws {NotFoundError} If user not found
- */
- async soft_delete( id, deleted_by_id ) {
+ async soft_delete(id, deleted_by_id) {
try {
- const user = await new (get_user_model())().find_one( { id }, [] );
- if (!user) throw new NotFoundError( 'User not found' );
- return await user.soft_delete( deleted_by_id );
+ const user = await new (get_user_model())().find_one({ id }, []);
+ if (!user) throw new NotFoundError('User not found');
+ return await user.soft_delete(deleted_by_id);
} catch (error) {
- logger.error( `Failed to soft delete user: ${ error.message }` );
+ logger.error(`Failed to soft delete user: ${error.message}`);
throw error;
}
},
- /**
- * Create a new User instance
- * @returns {User} User instance
- */
- instance:() => new (get_user_model())()
+ instance: () => new (get_user_model())()
},
- phone_number:{
- /**
- * Create a new phone number
- * @param {Object} phone_data - Phone number data
- * @returns {Promise<PhoneNumber>} Created phone number instance
- * @throws {ValidationError} If required fields are missing
- * @throws {FailedToCreateError} If creation fails
- */
- async create( phone_data ) {
+ phone_number: {
+ async create(phone_data) {
try {
- return await get_phone_number_model().create( phone_data );
+ return await get_phone_number_model().create(phone_data);
} catch (error) {
- logger.error( `Failed to create phone number: ${ error.message }` );
+ logger.error(`Failed to create phone number: ${error.message}`);
throw error;
}
},
- /**
- * Find phone number by number
- * @param {string} number - Phone number to search for
- * @param {string[]} [excludes] - Fields to exclude
- * @returns {Promise<PhoneNumber|null>} Phone number instance or null
- */
- async find_by_number( number, excludes ) {
+ async find_by_number(number, excludes) {
try {
- return await get_phone_number_model().find_by_number( number, excludes );
+ return await get_phone_number_model().find_by_number(number, excludes);
} catch (error) {
- logger.error( `Failed to find phone number: ${ error.message }` );
+ logger.error(`Failed to find phone number: ${error.message}`);
throw error;
}
},
- /**
- * Find one phone number
- * @param {Object} where - Conditions
- * @param {string[]} [excludes] - Fields to exclude
- * @returns {Promise<PhoneNumber|null>} Phone number instance or null
- */
- async find_one( where, excludes ) {
+ async find_one(where, excludes) {
try {
- return await new (get_phone_number_model())().find_one( where, excludes );
+ return await new (get_phone_number_model())().find_one(where, excludes);
} catch (error) {
- logger.error( `Failed to find one phone number: ${ error.message }` );
+ logger.error(`Failed to find one phone number: ${error.message}`);
throw error;
}
},
- /**
- * Find many phone numbers
- * @param {Object} [where] - Conditions
- * @param {string[]} [excludes] - Fields to exclude
- * @param {{name: string, direction?: 'asc'|'desc'}||null} [order_by] - Order by configuration
- * @param {number} [limit] - Maximum number of records
- * @param {number} [offset] - Number of records to skip
- * @returns {Promise<PhoneNumber[]>} Array of phone numbers
- */
- async find_many( where, excludes, order_by, limit, offset ) {
+ async find_many(where, excludes, order_by, limit, offset) {
try {
- return await new (get_phone_number_model())().find_many( where, excludes, order_by, limit, offset );
+ return await new (get_phone_number_model())().find_many(where, excludes, order_by, limit, offset);
} catch (error) {
- logger.error( `Failed to find many phone numbers: ${ error.message }` );
+ logger.error(`Failed to find many phone numbers: ${error.message}`);
throw error;
}
},
- /**
- * Create a new PhoneNumber instance
- * @returns {PhoneNumber} PhoneNumber instance
- */
- instance:() => new (get_phone_number_model())()
+ instance: () => new (get_phone_number_model())()
},
- user_phone_numbers:{
- /**
- * Add a user-phone number relation
- * @param {number|string} user_id - User ID
- * @param {number|string} phone_number_id - Phone number ID
- * @returns {Promise<UserPhoneNumber>} Created relation instance
- * @throws {ValidationError} If IDs are invalid
- * @throws {FailedToCreateError} If creation fails
- */
- async add_relation( user_id, phone_number_id ) {
+ user_phone_numbers: {
+ async add_relation(user_id, phone_number_id) {
try {
- return await get_user_phone_numbers_model().add_relation( user_id, phone_number_id );
+ return await get_user_phone_numbers_model().add_relation(user_id, phone_number_id);
} catch (error) {
- logger.error( `Failed to add user-phone number relation: ${ error.message }` );
+ logger.error(`Failed to add user-phone number relation: ${error.message}`);
throw error;
}
},
- /**
- * Remove a user-phone number relation
- * @param {number|string} phone_number_id - Phone number ID
- * @param {number|string|undefined} [user_id] - User ID
- * @returns {Promise<UserPhoneNumber|null>} Deleted relation instance or null
- * @throws {ValidationError} If IDs are invalid
- */
- async remove_relation( phone_number_id, user_id ) {
+ async remove_relation(phone_number_id, user_id) {
try {
- return await get_user_phone_numbers_model().remove_relation( phone_number_id, user_id );
+ return await get_user_phone_numbers_model().remove_relation(phone_number_id, user_id);
} catch (error) {
- logger.error( `Failed to remove user-phone number relation: ${ error.message }` );
+ logger.error(`Failed to remove user-phone number relation: ${error.message}`);
throw error;
}
},
- /**
- * Find user-phone number relation by IDs
- * @param {number|string} user_id - User ID
- * @param {number|string} phone_number_id - Phone number ID
- * @param {string[]} [excludes] - Fields to exclude
- * @returns {Promise<UserPhoneNumber|null>} Relation instance or null
- */
- async find_by_ids( user_id, phone_number_id, excludes ) {
+ async find_by_ids(user_id, phone_number_id, excludes) {
try {
- return await get_user_phone_numbers_model().find_by_ids( user_id, phone_number_id, excludes );
+ return await get_user_phone_numbers_model().find_by_ids(user_id, phone_number_id, excludes);
} catch (error) {
- logger.error( `Failed to find user-phone number by IDs: ${ error.message }` );
+ logger.error(`Failed to find user-phone number by IDs: ${error.message}`);
throw error;
}
},
- /**
- * Find user-phone number relations by user ID
- * @param {number|string} user_id - User ID
- * @param {string[]} [excludes] - Fields to exclude
- * @param {{name: string, direction?: 'asc'|'desc'}||null} [order_by] - Order by configuration
- * @param {number} [limit] - Maximum number of records
- * @param {number} [offset] - Number of records to skip
- * @returns {Promise<UserPhoneNumber[]>} Array of relations
- */
- async find_by_user_id( user_id, excludes, order_by, limit, offset ) {
+ async find_by_user_id(user_id, excludes, order_by, limit, offset) {
try {
- return await get_user_phone_numbers_model().find_by_user_id( user_id, excludes, order_by, limit, offset );
+ return await get_user_phone_numbers_model().find_by_user_id(user_id, excludes, order_by, limit, offset);
} catch (error) {
- logger.error( `Failed to find user-phone numbers by user ID: ${ error.message }` );
+ logger.error(`Failed to find user-phone numbers by user ID: ${error.message}`);
throw error;
}
},
- /**
- * Create a new UserPhoneNumber instance
- * @returns {UserPhoneNumber} UserPhoneNumber instance
- */
- instance:() => new (get_user_phone_numbers_model())()
+ instance: () => new (get_user_phone_numbers_model())()
},
- address:{
- /**
- * Create a new address
- * @param {Object} address_data - Address data
- * @returns {Promise<Address>} Created address instance
- * @throws {ValidationError} If required fields are missing
- * @throws {FailedToCreateError} If creation fails
- */
- async create( address_data ) {
+ address: {
+ async create(address_data) {
try {
- return await get_address_model().create( address_data );
+ return await get_address_model().create(address_data);
} catch (error) {
- logger.error( `Failed to create address: ${ error.message }` );
+ logger.error(`Failed to create address: ${error.message}`);
throw error;
}
},
- /**
- * Find address by zip code
- * @param {string} zip_code - Zip code to search for
- * @param {string[]} [excludes] - Fields to exclude
- * @returns {Promise<Address|null>} Address instance or null
- */
- async find_by_zip_code( zip_code, excludes ) {
+ async find_by_zip_code(zip_code, excludes) {
try {
- return await get_address_model().find_by_zip_code( zip_code, excludes );
+ return await get_address_model().find_by_zip_code(zip_code, excludes);
} catch (error) {
- logger.error( `Failed to find address by zip code: ${ error.message }` );
+ logger.error(`Failed to find address by zip code: ${error.message}`);
throw error;
}
},
- /**
- * Find one address
- * @param {Object} where - Conditions
- * @param {string[]} [excludes] - Fields to exclude
- * @returns {Promise<Address|null>} Address instance or null
- */
- async find_one( where, excludes ) {
+ async find_one(where, excludes) {
try {
- return await new (get_address_model())().find_one( where, excludes );
+ return await new (get_address_model())().find_one(where, excludes);
} catch (error) {
- logger.error( `Failed to find one address: ${ error.message }` );
+ logger.error(`Failed to find one address: ${error.message}`);
throw error;
}
},
- /**
- * Find many addresses
- * @param {Object} [where] - Conditions
- * @param {string[]} [excludes] - Fields to exclude
- * @param {{name: string, direction?: 'asc'|'desc'}||null} [order_by] - Order by configuration
- * @param {number} [limit] - Maximum number of records
- * @param {number} [offset] - Number of records to skip
- * @returns {Promise<Address[]>} Array of addresses
- */
- async find_many( where, excludes, order_by, limit, offset ) {
+ async find_many(where, excludes, order_by, limit, offset) {
try {
- return await new (get_address_model())().find_many( where, excludes, order_by, limit, offset );
+ return await new (get_address_model())().find_many(where, excludes, order_by, limit, offset);
} catch (error) {
- logger.error( `Failed to find many addresses: ${ error.message }` );
+ logger.error(`Failed to find many addresses: ${error.message}`);
throw error;
}
},
- /**
- * Create a new Address instance
- * @returns {Address} Address instance
- */
- instance:() => new (get_address_model())()
+ instance: () => new (get_address_model())()
},
- user_addresses:{
- /**
- * Add a user-address relation
- * @param {number|string} user_id - User ID
- * @param {number|string} address_id - Address ID
- * @returns {Promise<UserAddress>} Created relation instance
- * @throws {ValidationError} If IDs are invalid
- * @throws {FailedToCreateError} If creation fails
- */
- async add_relation( user_id, address_id ) {
+ user_addresses: {
+ async add_relation(user_id, address_id) {
try {
- return await get_user_addresses_model().add_relation( user_id, address_id );
+ return await get_user_addresses_model().add_relation(user_id, address_id);
} catch (error) {
- logger.error( `Failed to add user-address relation: ${ error.message }` );
+ logger.error(`Failed to add user-address relation: ${error.message}`);
throw error;
}
},
- /**
- * Remove a user-address relation
- * @param {number|string} address_id - Address ID
- * @param {number|string|undefined} [user_id] - User ID
- * @returns {Promise<UserAddress|null>} Deleted relation instance or null
- * @throws {ValidationError} If IDs are invalid
- */
- async remove_relation( address_id, user_id ) {
+ async remove_relation(address_id, user_id) {
try {
- return await get_user_addresses_model().remove_relation( address_id, user_id );
+ return await get_user_addresses_model().remove_relation(address_id, user_id);
} catch (error) {
- logger.error( `Failed to remove user-address relation: ${ error.message }` );
+ logger.error(`Failed to remove user-address relation: ${error.message}`);
throw error;
}
},
- /**
- * Find user-address relation by IDs
- * @param {number|string} user_id - User ID
- * @param {number|string} address_id - Address ID
- * @param {string[]} [excludes] - Fields to exclude
- * @returns {Promise<UserAddress|null>} Relation instance or null
- */
- async find_by_ids( user_id, address_id, excludes ) {
+ async find_by_ids(user_id, address_id, excludes) {
try {
- return await get_user_addresses_model().find_by_ids( user_id, address_id, excludes );
+ return await get_user_addresses_model().find_by_ids(user_id, address_id, excludes);
} catch (error) {
- logger.error( `Failed to find user-address by IDs: ${ error.message }` );
+ logger.error(`Failed to find user-address by IDs: ${error.message}`);
throw error;
}
},
- /**
- * Find user-address relations by user ID
- * @param {number|string} user_id - User ID
- * @param {string[]} [excludes] - Fields to exclude
- * @param {{name: string, direction?: 'asc'|'desc'}||null} [order_by] - Order by configuration
- * @param {number} [limit] - Maximum number of records
- * @param {number} [offset] - Number of records to skip
- * @returns {Promise<UserAddress[]>} Array of relations
- */
- async find_by_user_id( user_id, excludes, order_by, limit, offset ) {
+ async find_by_user_id(user_id, excludes, order_by, limit, offset) {
try {
- return await get_user_addresses_model().find_by_user_id( user_id, excludes, order_by, limit, offset );
+ return await get_user_addresses_model().find_by_user_id(user_id, excludes, order_by, limit, offset);
} catch (error) {
- logger.error( `Failed to find user-addresses by user ID: ${ error.message }` );
+ logger.error(`Failed to find user-addresses by user ID: ${error.message}`);
throw error;
}
},
- /**
- * Create a new UserAddress instance
- * @returns {UserAddress} UserAddress instance
- */
- instance:() => new (get_user_addresses_model())()
+ instance: () => new (get_user_addresses_model())()
},
- authentication:{
- /**
- * Create a new authentication record
- * @param {Object} auth_data - Authentication data
- * @returns {Promise<Authentication>} Created authentication instance
- * @throws {ValidationError} If required fields are missing
- * @throws {FailedToCreateError} If creation fails
- */
- async create( auth_data ) {
+ authentication: {
+ async create(auth_data) {
try {
- return await get_authentication_model().create( auth_data );
+ return await get_authentication_model().create(auth_data);
} catch (error) {
- logger.error( `Failed to create authentication record: ${ error.message }` );
+ logger.error(`Failed to create authentication record: ${error.message}`);
throw error;
}
},
- /**
- * Find authentication record by user ID
- * @param {number|string} user_id - User ID
- * @param {string[]} [excludes] - Fields to exclude
- * @returns {Promise<Authentication|null>} Authentication instance or null
- */
- async find_by_user_id( user_id, excludes ) {
+ async find_by_user_id(user_id, excludes) {
try {
- return await get_authentication_model().find_by_user_id( user_id, excludes );
+ return await get_authentication_model().find_by_user_id(user_id, excludes);
} catch (error) {
- logger.error( `Failed to find authentication by user ID: ${ error.message }` );
+ logger.error(`Failed to find authentication by user ID: ${error.message}`);
throw error;
}
},
- /**
- * Find authentication record by reset token
- * @param {string} token - Password reset token
- * @param {string[]} [excludes] - Fields to exclude
- * @returns {Promise<Authentication|null>} Authentication instance or null
- */
- async find_by_reset_token( token, excludes ) {
+ async find_by_reset_token(token, excludes) {
try {
- return await get_authentication_model().find_by_reset_token( token, excludes );
+ return await get_authentication_model().find_by_reset_token(token, excludes);
} catch (error) {
- logger.error( `Failed to find authentication by reset token: ${ error.message }` );
+ logger.error(`Failed to find authentication by reset token: ${error.message}`);
throw error;
}
},
- /**
- * Find one authentication record
- * @param {Object} where - Conditions
- * @param {string[]} [excludes] - Fields to exclude
- * @returns {Promise<Authentication|null>} Authentication instance or null
- */
- async find_one( where, excludes ) {
+ async find_one(where, excludes) {
try {
- return await new (get_authentication_model())().find_one( where, excludes );
+ return await new (get_authentication_model())().find_one(where, excludes);
} catch (error) {
- logger.error( `Failed to find one authentication record: ${ error.message }` );
+ logger.error(`Failed to find one authentication record: ${error.message}`);
throw error;
}
},
- /**
- * Find many authentication records
- * @param {Object} [where] - Conditions
- * @param {string[]} [excludes] - Fields to exclude
- * @param {{name: string, direction?: 'asc'|'desc'}||null} [order_by] - Order by configuration
- * @param {number} [limit] - Maximum number of records
- * @param {number} [offset] - Number of records to skip
- * @returns {Promise<Authentication[]>} Array of authentication records
- */
- async find_many( where, excludes, order_by, limit, offset ) {
+ async find_many(where, excludes, order_by, limit, offset) {
try {
- return await new (get_authentication_model())().find_many( where, excludes, order_by, limit, offset );
+ return await new (get_authentication_model())().find_many(where, excludes, order_by, limit, offset);
} catch (error) {
- logger.error( `Failed to find many authentication records: ${ error.message }` );
+ logger.error(`Failed to find many authentication records: ${error.message}`);
throw error;
}
},
- /**
- * Lock authentication account
- * @param {number|string} id - Authentication ID
- * @returns {Promise<Authentication>} Updated authentication instance
- * @throws {NotFoundError} If authentication record not found
- */
- async lock_account( id ) {
+ async lock_account(id) {
try {
- const auth = await new (get_authentication_model())().find_one( { id }, [] );
- if (!auth) throw new NotFoundError( 'Authentication record not found' );
+ const auth = await new (get_authentication_model())().find_one({ id }, []);
+ if (!auth) throw new NotFoundError('Authentication record not found');
return await auth.lock_account();
} catch (error) {
- logger.error( `Failed to lock account: ${ error.message }` );
+ logger.error(`Failed to lock account: ${error.message}`);
throw error;
}
},
- /**
- * Unlock authentication account
- * @param {number|string} id - Authentication ID
- * @returns {Promise<Authentication>} Updated authentication instance
- * @throws {NotFoundError} If authentication record not found
- */
- async unlock_account( id ) {
+ async unlock_account(id) {
try {
- const auth = await new (get_authentication_model())().find_one( { id }, [] );
- if (!auth) throw new NotFoundError( 'Authentication record not found' );
+ const auth = await new (get_authentication_model())().find_one({ id }, []);
+ if (!auth) throw new NotFoundError('Authentication record not found');
return await auth.unlock_account();
} catch (error) {
- logger.error( `Failed to unlock account: ${ error.message }` );
+ logger.error(`Failed to unlock account: ${error.message}`);
throw error;
}
},
- /**
- * Soft delete authentication record
- * @param {number|string} id - Authentication ID
- * @param {number|string} deleted_by_id - ID of user performing deletion
- * @returns {Promise<Authentication>} Updated authentication instance
- * @throws {NotFoundError} If authentication record not found
- */
- async soft_delete( id, deleted_by_id ) {
+ async soft_delete(id, deleted_by_id) {
try {
- const auth = await new (get_authentication_model())().find_one( { id }, [] );
- if (!auth) throw new NotFoundError( 'Authentication record not found' );
- return await auth.soft_delete( deleted_by_id );
+ const auth = await new (get_authentication_model())().find_one({ id }, []);
+ if (!auth) throw new NotFoundError('Authentication record not found');
+ return await auth.soft_delete(deleted_by_id);
} catch (error) {
- logger.error( `Failed to soft delete authentication: ${ error.message }` );
+ logger.error(`Failed to soft delete authentication: ${error.message}`);
throw error;
}
},
- /**
- * Create a new Authentication instance
- * @returns {Authentication} Authentication instance
- */
- instance:() => new (get_authentication_model())()
+ instance: () => new (get_authentication_model())()
},
- role:{
- /**
- * Create a new role
- * @param {Object} role_data - Role data
- * @returns {Promise<Role>} Created role instance
- * @throws {ValidationError} If required fields are missing
- * @throws {FailedToCreateError} If creation fails
- */
- async create( role_data ) {
+ role: {
+ async create(role_data) {
try {
- return await get_role_model().create( role_data );
+ return await get_role_model().create(role_data);
} catch (error) {
- logger.error( `Failed to create role: ${ error.message }` );
+ logger.error(`Failed to create role: ${error.message}`);
throw error;
}
},
- /**
- * Find role by name
- * @param {string} name - Role name to search for
- * @param {string[]} [excludes] - Fields to exclude
- * @returns {Promise<Role|null>} Role instance or null
- */
- async find_by_name( name, excludes ) {
+ async find_by_name(name, excludes) {
try {
- return await get_role_model().find_by_name( name, excludes );
+ return await get_role_model().find_by_name(name, excludes);
} catch (error) {
- logger.error( `Failed to find role by name: ${ error.message }` );
+ logger.error(`Failed to find role by name: ${error.message}`);
throw error;
}
},
- /**
- * Find one role
- * @param {Object} where - Conditions
- * @param {string[]} [excludes] - Fields to exclude
- * @returns {Promise<Role|null>} Role instance or null
- */
- async find_one( where, excludes ) {
+ async find_one(where, excludes) {
try {
- return await new (get_role_model())().find_one( where, excludes );
+ return await new (get_role_model())().find_one(where, excludes);
} catch (error) {
- logger.error( `Failed to find one role: ${ error.message }` );
+ logger.error(`Failed to find one role: ${error.message}`);
throw error;
}
},
- /**
- * Find many roles
- * @param {Object} [where] - Conditions
- * @param {string[]} [excludes] - Fields to exclude
- * @param {{name: string, direction?: 'asc'|'desc'}||null} [order_by] - Order by configuration
- * @param {number} [limit] - Maximum number of records
- * @param {number} [offset] - Number of records to skip
- * @returns {Promise<Role[]>} Array of roles
- */
- async find_many( where, excludes, order_by, limit, offset ) {
+ async find_many(where, excludes, order_by, limit, offset) {
try {
- return await new (get_role_model())().find_many( where, excludes, order_by, limit, offset );
+ return await new (get_role_model())().find_many(where, excludes, order_by, limit, offset);
} catch (error) {
- logger.error( `Failed to find many roles: ${ error.message }` );
+ logger.error(`Failed to find many roles: ${error.message}`);
throw error;
}
},
- /**
- * Create a new Role instance
- * @returns {Role} Role instance
- */
- instance:() => new (get_role_model())()
+ instance: () => new (get_role_model())()
},
- user_roles:{
- /**
- * Add a user-role relation
- * @param {number|string} user_id - User ID
- * @param {number|string} role_id - Role ID
- * @returns {Promise<UserRole>} Created relation instance
- * @throws {ValidationError} If IDs are invalid
- * @throws {FailedToCreateError} If creation fails
- */
- async add_relation( user_id, role_id ) {
+ user_roles: {
+ async add_relation(user_id, role_id) {
+ try {
+ return await get_user_roles_model().add_relation(user_id, role_id);
+ } catch (error) {
+ logger.error(`Failed to add user-role relation: ${error.message}`);
+ throw error;
+ }
+ },
+ async remove_relation(role_id, user_id) {
+ try {
+ return await get_user_roles_model().remove_relation(role_id, user_id);
+ } catch (error) {
+ logger.error(`Failed to remove user-role relation: ${error.message}`);
+ throw error;
+ }
+ },
+ async find_by_ids(user_id, role_id, excludes) {
+ try {
+ return await get_user_roles_model().find_by_ids(user_id, role_id, excludes);
+ } catch (error) {
+ logger.error(`Failed to find user-role by IDs: ${error.message}`);
+ throw error;
+ }
+ },
+ async find_by_user_id(user_id, excludes, order_by, limit, offset) {
+ try {
+ return await get_user_roles_model().find_by_user_id(user_id, excludes, order_by, limit, offset);
+ } catch (error) {
+ logger.error(`Failed to find user-roles by user ID: ${error.message}`);
+ throw error;
+ }
+ },
+ instance: () => new (get_user_roles_model())()
+ },
+ media: {
+ async create(media_data) {
+ try {
+ return await get_media_model().create(media_data);
+ } catch (error) {
+ logger.error(`Failed to create media: ${error.message}`);
+ throw error;
+ }
+ },
+ async find_by_file_path(file_path, excludes) {
+ try {
+ return await get_media_model().find_by_file_path(file_path, excludes);
+ } catch (error) {
+ logger.error(`Failed to find media by file path: ${error.message}`);
+ throw error;
+ }
+ },
+ async find_one(where, excludes) {
+ try {
+ return await new (get_media_model())().find_one(where, excludes);
+ } catch (error) {
+ logger.error(`Failed to find one media: ${error.message}`);
+ throw error;
+ }
+ },
+ async find_many(where, excludes, order_by, limit, offset) {
+ try {
+ return await new (get_media_model())().find_many(where, excludes, order_by, limit, offset);
+ } catch (error) {
+ logger.error(`Failed to find many media: ${error.message}`);
+ throw error;
+ }
+ },
+ instance: () => new (get_media_model())()
+ },
+ post: {
+ async create(post_data) {
+ try {
+ return await get_post_model().create(post_data);
+ } catch (error) {
+ logger.error(`Failed to create post: ${error.message}`);
+ throw error;
+ }
+ },
+ async find_by_title(title, excludes) {
+ try {
+ return await get_post_model().find_by_title(title, excludes);
+ } catch (error) {
+ logger.error(`Failed to find post by title: ${error.message}`);
+ throw error;
+ }
+ },
+ async find_one(where, excludes) {
+ try {
+ return await new (get_post_model())().find_one(where, excludes);
+ } catch (error) {
+ logger.error(`Failed to find one post: ${error.message}`);
+ throw error;
+ }
+ },
+ async find_many(where, excludes, order_by, limit, offset) {
+ try {
+ return await new (get_post_model())().find_many(where, excludes, order_by, limit, offset);
+ } catch (error) {
+ logger.error(`Failed to find many posts: ${error.message}`);
+ throw error;
+ }
+ },
+ instance: () => new (get_post_model())()
+ },
+ message_group: {
+ async create(message_group_data) {
+ try {
+ return await get_message_group_model().create(message_group_data);
+ } catch (error) {
+ logger.error(`Failed to create message group: ${error.message}`);
+ throw error;
+ }
+ },
+ async find_one(where, excludes) {
+ try {
+ return await new (get_message_group_model())().find_one(where, excludes);
+ } catch (error) {
+ logger.error(`Failed to find one message group: ${error.message}`);
+ throw error;
+ }
+ },
+ async find_many(where, excludes, order_by, limit, offset) {
+ try {
+ return await new (get_message_group_model())().find_many(where, excludes, order_by, limit, offset);
+ } catch (error) {
+ logger.error(`Failed to find many message groups: ${error.message}`);
+ throw error;
+ }
+ },
+ instance: () => new (get_message_group_model())()
+ },
+ message_group_members: {
+ async add_relation(group_id, user_id) {
+ try {
+ return await get_message_group_members_model().add_relation(group_id, user_id);
+ } catch (error) {
+ logger.error(`Failed to add message group member relation: ${error.message}`);
+ throw error;
+ }
+ },
+ async remove_relation(user_id, group_id) {
+ try {
+ return await get_message_group_members_model().remove_relation(user_id, group_id);
+ } catch (error) {
+ logger.error(`Failed to remove message group member relation: ${error.message}`);
+ throw error;
+ }
+ },
+ async find_by_ids(group_id, user_id, excludes) {
+ try {
+ return await get_message_group_members_model().find_by_ids(group_id, user_id, excludes);
+ } catch (error) {
+ logger.error(`Failed to find message group member by IDs: ${error.message}`);
+ throw error;
+ }
+ },
+ async find_by_group_id(group_id, excludes, order_by, limit, offset) {
+ try {
+ return await get_message_group_members_model().find_by_group_id(group_id, excludes, order_by, limit, offset);
+ } catch (error) {
+ logger.error(`Failed to find message group members by group ID: ${error.message}`);
+ throw error;
+ }
+ },
+ instance: () => new (get_message_group_members_model())()
+ },
+ message: {
+ async create(message_data) {
+ try {
+ return await get_message_model().create(message_data);
+ } catch (error) {
+ logger.error(`Failed to create message: ${error.message}`);
+ throw error;
+ }
+ },
+ async find_by_group_id(group_id, excludes, order_by, limit, offset) {
+ try {
+ return await get_message_model().find_by_group_id(group_id, excludes, order_by, limit, offset);
+ } catch (error) {
+ logger.error(`Failed to find messages by group ID: ${error.message}`);
+ throw error;
+ }
+ },
+ async find_by_recipient_id(recipient_id, excludes, order_by, limit, offset) {
try {
- return await get_user_roles_model().add_relation( user_id, role_id );
+ return await get_message_model().find_by_recipient_id(recipient_id, excludes, order_by, limit, offset);
} catch (error) {
- logger.error( `Failed to add user-role relation: ${ error.message }` );
+ logger.error(`Failed to find messages by recipient ID: ${error.message}`);
throw error;
}
},
- /**
- * Remove a user-role relation
- * @param {number|string} role_id - Role ID
- * @param {number|string|undefined} [user_id] - User ID
- * @returns {Promise<UserRole|null>} Deleted relation instance or null
- * @throws {ValidationError} If IDs are invalid
- */
- async remove_relation( role_id, user_id ) {
+ async find_one(where, excludes) {
try {
- return await get_user_roles_model().remove_relation( role_id, user_id );
+ return await new (get_message_model())().find_one(where, excludes);
} catch (error) {
- logger.error( `Failed to remove user-role relation: ${ error.message }` );
+ logger.error(`Failed to find one message: ${error.message}`);
throw error;
}
},
- /**
- * Find user-role relation by IDs
- * @param {number|string} user_id - User ID
- * @param {number|string} role_id - Role ID
- * @param {string[]} [excludes] - Fields to exclude
- * @returns {Promise<UserRole|null>} Relation instance or null
- */
- async find_by_ids( user_id, role_id, excludes ) {
+ async find_many(where, excludes, order_by, limit, offset) {
try {
- return await get_user_roles_model().find_by_ids( user_id, role_id, excludes );
+ return await new (get_message_model())().find_many(where, excludes, order_by, limit, offset);
} catch (error) {
- logger.error( `Failed to find user-role by IDs: ${ error.message }` );
+ logger.error(`Failed to find many messages: ${error.message}`);
throw error;
}
},
- /**
- * Find user-role relations by user ID
- * @param {number|string} user_id - User ID
- * @param {string[]} [excludes] - Fields to exclude
- * @param {{name: string, direction?: 'asc'|'desc'}||null} [order_by] - Order by configuration
- * @param {number} [limit] - Maximum number of records
- * @param {number} [offset] - Number of records to skip
- * @returns {Promise<UserRole[]>} Array of relations
- */
- async find_by_user_id( user_id, excludes, order_by, limit, offset ) {
+ async mark_as_read(id) {
try {
- return await get_user_roles_model().find_by_user_id( user_id, excludes, order_by, limit, offset );
+ const message = await new (get_message_model())().find_one({ id }, []);
+ if (!message) throw new NotFoundError('Message not found');
+ return await message.mark_as_read();
} catch (error) {
- logger.error( `Failed to find user-roles by user ID: ${ error.message }` );
+ logger.error(`Failed to mark message as read: ${error.message}`);
throw error;
}
},
- /**
- * Create a new UserRole instance
- * @returns {UserRole} UserRole instance
- */
- instance:() => new (get_user_roles_model())()
+ instance: () => new (get_message_model())()
}
};
--- /dev/null
+/**
+ * @file Media model for phase.media table
+ */
+
+const { Model, NotFoundError, ValidationError, FailedToCreateError } = require('./model');
+
+/**
+ * @typedef {Object} Media
+ * @property {number} id - Media ID (primary key)
+ * @property {number} user_id - User ID (foreign key)
+ * @property {string} file_path - File path
+ * @property {string} file_type - File type (e.g., 'image', 'video')
+ * @property {string} visibility - Visibility (e.g., 'private', 'family', 'public')
+ * @property {number|null} created_by_id - ID of user who created this media
+ * @property {Date} created_at - Creation timestamp
+ * @property {boolean} is_deleted - Soft delete flag
+ * @property {number|null} deleted_by_id - ID of user who deleted this media
+ * @property {Date|null} deleted_at - Deletion timestamp
+ */
+
+/**
+ * Media model class
+ * @extends Model
+ */
+class Media extends Model {
+ /**
+ * Create a Media instance
+ * @param {Partial<Media>} [props] - Media properties
+ */
+ constructor(props) {
+ super(props);
+ this.table = 'phase.media';
+ this.prepend = 'm';
+ this.default_columns = [
+ 'id', 'user_id', 'file_path', 'file_type', 'visibility',
+ 'created_by_id', 'created_at', 'is_deleted', 'deleted_by_id', 'deleted_at'
+ ];
+ this.update_exclude_columns = ['id', 'created_at', 'is_deleted', 'deleted_at', 'deleted_by_id'];
+ this.base_query = `
+ SELECT m.id, m.user_id, m.file_path, m.file_type, m.visibility,
+ m.created_by_id, m.created_at, m.is_deleted, m.deleted_by_id, m.deleted_at
+ FROM phase.media m
+ WHERE m.is_deleted = false
+ `;
+ this.base_list_query = `
+ SELECT m.id, m.user_id, m.file_path, m.file_type, m.visibility,
+ m.created_by_id, m.created_at
+ FROM phase.media m
+ WHERE m.is_deleted = false
+ `;
+ this.default_order_by = 'ORDER BY m.created_at DESC';
+ this.instance = _props => new Media(_props);
+ }
+
+ /**
+ * Create a new media
+ * @param {Omit<Media, 'id'|'created_at'|'is_deleted'|'deleted_by_id'|'deleted_at'>} media_data - Media data
+ * @returns {Promise<Media>} Created media instance
+ * @throws {ValidationError} If required fields are missing
+ * @throws {FailedToCreateError} If creation fails
+ */
+ static async create(media_data) {
+ const { user_id, file_path, file_type, visibility = 'private', created_by_id = null } = media_data;
+ if (!user_id || !file_path || !file_type) {
+ throw new ValidationError('Missing required fields: user_id, file_path, file_type');
+ }
+ const query_str = `
+ INSERT INTO phase.media (user_id, file_path, file_type, visibility, created_by_id)
+ VALUES ($1, $2, $3, $4, $5) RETURNING *;
+ `;
+ const values = [user_id, file_path, file_type, visibility, created_by_id];
+ const result = await phsdb.query(query_str, values, { plain: true });
+ if (!result) throw new FailedToCreateError('Failed to create media');
+ return new Media(result);
+ }
+
+ /**
+ * Find media by file path
+ * @param {string} file_path - File path to search for
+ * @param {string[]} [excludes] - Fields to exclude from result
+ * @returns {Promise<Media|null>} Media instance or null
+ */
+ static async find_by_file_path(file_path, excludes = []) {
+ return await new Media().find_one({ file_path }, excludes);
+ }
+
+ /**
+ * Soft delete media
+ * @param {number|string} deleted_by_id - ID of user performing deletion
+ * @returns {Promise<Media>} Updated media instance
+ * @throws {ValidationError} If deleted_by_id is invalid
+ * @throws {NotFoundError} If record not found
+ */
+ async soft_delete(deleted_by_id) {
+ const deleted_by_id_int = parseInt(deleted_by_id, 10);
+ if (isNaN(deleted_by_id_int)) {
+ throw new ValidationError('deleted_by_id must be a valid integer');
+ }
+ return await this.update({
+ is_deleted: true,
+ deleted_at: new Date().toISOString(),
+ deleted_by_id: deleted_by_id_int
+ });
+ }
+}
+
+module.exports = Media;
\ No newline at end of file
--- /dev/null
+/**
+ * @file Message model for phase.messages table
+ */
+
+const { Model, NotFoundError, ValidationError, FailedToCreateError } = require('./model');
+
+/**
+ * @typedef {Object} Message
+ * @property {number} id - Message ID (primary key)
+ * @property {number} sender_id - Sender ID (foreign key to users)
+ * @property {number|null} group_id - Group ID (foreign key to message_groups)
+ * @property {number|null} recipient_id - Recipient ID (foreign key to users)
+ * @property {string} content - Message content
+ * @property {boolean} read - Whether the message has been read
+ * @property {Date|null} read_at - Timestamp when the message was read
+ * @property {Date} created_at - Creation timestamp
+ */
+
+/**
+ * Message model class
+ * @extends Model
+ */
+class Message extends Model {
+ /**
+ * Create a Message instance
+ * @param {Partial<Message>} [props] - Message properties
+ */
+ constructor(props) {
+ super(props);
+ this.table = 'phase.messages';
+ this.prepend = 'm';
+ this.default_columns = [
+ 'id', 'sender_id', 'group_id', 'recipient_id', 'content',
+ 'read', 'read_at', 'created_at'
+ ];
+ this.update_exclude_columns = ['id', 'created_at'];
+ this.base_query = `
+ SELECT m.id, m.sender_id, m.group_id, m.recipient_id, m.content,
+ m.read, m.read_at, m.created_at
+ FROM phase.messages m
+ `;
+ this.base_list_query = this.base_query;
+ this.default_order_by = 'ORDER BY m.created_at DESC';
+ this.instance = _props => new Message(_props);
+ }
+
+ /**
+ * Create a new message
+ * @param {Omit<Message, 'id'|'created_at'|'read'|'read_at'>} message_data - Message data
+ * @returns {Promise<Message>} Created message instance
+ * @throws {ValidationError} If required fields are missing
+ * @throws {FailedToCreateError} If creation fails
+ */
+ static async create(message_data) {
+ const { sender_id, group_id, recipient_id, content } = message_data;
+ if (!sender_id || !content || (group_id == null && recipient_id == null)) {
+ throw new ValidationError('Missing required fields: sender_id, content, and either group_id or recipient_id');
+ }
+ const query_str = `
+ INSERT INTO phase.messages (sender_id, group_id, recipient_id, content, read, read_at)
+ VALUES ($1, $2, $3, $4, FALSE, NULL) RETURNING *;
+ `;
+ const values = [sender_id, group_id, recipient_id, content];
+ const result = await phsdb.query(query_str, values, { plain: true });
+ if (!result) throw new FailedToCreateError('Failed to create message');
+ return new Message(result);
+ }
+
+ /**
+ * Find messages by group ID
+ * @param {number|string} group_id - Group ID
+ * @param {string[]} [excludes] - Fields to exclude from result
+ * @param {{name: string, direction?: 'asc'|'desc'}||null} [order_by] - Order by configuration
+ * @param {number} [limit=100] - Maximum number of records
+ * @param {number} [offset=0] - Number of records to skip
+ * @returns {Promise<Message[]>} Array of messages
+ */
+ static async find_by_group_id(group_id, excludes = [], order_by = null, limit = 100, offset = 0) {
+ return await new Message().find_many({ group_id }, excludes, order_by, limit, offset);
+ }
+
+ /**
+ * Find messages by recipient ID
+ * @param {number|string} recipient_id - Recipient ID
+ * @param {string[]} [excludes] - Fields to exclude from result
+ * @param {{name: string, direction?: 'asc'|'desc'}||null} [order_by] - Order by configuration
+ * @param {number} [limit=100] - Maximum number of records
+ * @param {number} [offset=0] - Number of records to skip
+ * @returns {Promise<Message[]>} Array of messages
+ */
+ static async find_by_recipient_id(recipient_id, excludes = [], order_by = null, limit = 100, offset = 0) {
+ return await new Message().find_many({ recipient_id }, excludes, order_by, limit, offset);
+ }
+
+ /**
+ * Mark a message as read
+ * @returns {Promise<Message>} Updated message instance
+ * @throws {NotFoundError} If record not found
+ */
+ async mark_as_read() {
+ return await this.update({
+ read: true,
+ read_at: new Date().toISOString()
+ });
+ }
+}
+
+module.exports = Message;
\ No newline at end of file
--- /dev/null
+/**
+ * @file Message group model for phase.message_groups table
+ */
+
+const { Model, ValidationError, FailedToCreateError } = require('./model');
+
+/**
+ * @typedef {Object} MessageGroup
+ * @property {number} id - Message group ID (primary key)
+ * @property {string} name - Message group name
+ * @property {number} created_by_id - ID of user who created this message group
+ * @property {Date} created_at - Creation timestamp
+ */
+
+/**
+ * Message group model class
+ * @extends Model
+ */
+class MessageGroup extends Model {
+ /**
+ * Create a MessageGroup instance
+ * @param {Partial<MessageGroup>} [props] - Message group properties
+ */
+ constructor(props) {
+ super(props);
+ this.table = 'phase.message_groups';
+ this.prepend = 'mg';
+ this.default_columns = [
+ 'id', 'name', 'created_by_id', 'created_at'
+ ];
+ this.update_exclude_columns = ['id', 'created_at'];
+ this.base_query = `
+ SELECT mg.id, mg.name, mg.created_by_id, mg.created_at
+ FROM phase.message_groups mg
+ `;
+ this.base_list_query = this.base_query;
+ this.default_order_by = 'ORDER BY mg.created_at DESC';
+ this.instance = _props => new MessageGroup(_props);
+ }
+
+ /**
+ * Create a new message group
+ * @param {Omit<MessageGroup, 'id'|'created_at'>} message_group_data - Message group data
+ * @returns {Promise<MessageGroup>} Created message group instance
+ * @throws {ValidationError} If required fields are missing
+ * @throws {FailedToCreateError} If creation fails
+ */
+ static async create(message_group_data) {
+ const { name, created_by_id } = message_group_data;
+ if (!name || !created_by_id) {
+ throw new ValidationError('Missing required fields: name, created_by_id');
+ }
+ const query_str = `
+ INSERT INTO phase.message_groups (name, created_by_id)
+ VALUES ($1, $2) RETURNING *;
+ `;
+ const values = [name, created_by_id];
+ const result = await phsdb.query(query_str, values, { plain: true });
+ if (!result) throw new FailedToCreateError('Failed to create message group');
+ return new MessageGroup(result);
+ }
+}
+
+module.exports = MessageGroup;
\ No newline at end of file
--- /dev/null
+/**
+ * @file Message group members model for phase.message_group_members table
+ */
+
+const { Model, ValidationError, FailedToCreateError } = require('./model');
+
+/**
+ * @typedef {Object} MessageGroupMember
+ * @property {number} group_id - Message group ID (foreign key)
+ * @property {number} user_id - User ID (foreign key)
+ */
+
+/**
+ * Message group member model class
+ * @extends Model
+ */
+class MessageGroupMember extends Model {
+ /**
+ * Create a MessageGroupMember instance
+ * @param {Partial<MessageGroupMember>} [props] - Message group member properties
+ */
+ constructor(props) {
+ super(props);
+ this.table = 'phase.message_group_members';
+ this.prepend = 'mgm';
+ this.default_columns = ['group_id', 'user_id'];
+ this.update_exclude_columns = ['group_id', 'user_id'];
+ this.base_query = `
+ SELECT mgm.group_id, mgm.user_id
+ FROM phase.message_group_members mgm
+ `;
+ this.base_list_query = this.base_query;
+ this.default_order_by = 'ORDER BY mgm.group_id ASC';
+ this.instance = _props => new MessageGroupMember(_props);
+ }
+
+ /**
+ * Add a message group member relation
+ * @param {number|string} group_id - Message group ID
+ * @param {number|string} user_id - User ID
+ * @returns {Promise<MessageGroupMember>} Created relation instance
+ * @throws {ValidationError} If IDs are invalid
+ * @throws {FailedToCreateError} If creation fails
+ */
+ static async add_relation(group_id, user_id) {
+ const group_id_int = parseInt(group_id, 10);
+ const user_id_int = parseInt(user_id, 10);
+ if (isNaN(group_id_int) || isNaN(user_id_int)) {
+ throw new ValidationError('group_id and user_id must be valid integers');
+ }
+ const query_str = `
+ INSERT INTO phase.message_group_members (group_id, user_id)
+ VALUES ($1, $2) RETURNING *;
+ `;
+ const values = [group_id_int, user_id_int];
+ const result = await phsdb.query(query_str, values, { plain: true });
+ if (!result) throw new FailedToCreateError('Failed to add message group member relation');
+ return new MessageGroupMember(result);
+ }
+
+ /**
+ * Remove a message group member relation
+ * @param {number|string} user_id - User ID
+ * @param {number|string|undefined} [group_id=undefined] - Message group ID
+ * @returns {Promise<MessageGroupMember|null>} Deleted relation instance or null
+ * @throws {ValidationError} If IDs are invalid
+ */
+ static async remove_relation(user_id, group_id = undefined) {
+ const group_id_int = parseInt(group_id, 10);
+ const user_id_int = parseInt(user_id, 10);
+ if (isNaN(user_id_int)) {
+ throw new ValidationError('user_id must be a valid integer');
+ }
+ let query_str = `
+ DELETE FROM phase.message_group_members
+ WHERE user_id = $1 ${group_id_int ? 'AND group_id = $2' : ''} RETURNING *;
+ `;
+ const values = [user_id_int];
+ if (!isNaN(group_id_int)) values.push(group_id_int);
+ const result = await phsdb.query(query_str, values, { plain: !isNaN(group_id_int) });
+ return result ? new MessageGroupMember(result) : null;
+ }
+
+ /**
+ * Find message group member relation by IDs
+ * @param {number|string} group_id - Message group ID
+ * @param {number|string} user_id - User ID
+ * @param {string[]} [excludes] - Fields to exclude from result
+ * @returns {Promise<MessageGroupMember|null>} Relation instance or null
+ */
+ static async find_by_ids(group_id, user_id, excludes = []) {
+ return await new MessageGroupMember().find_one(
+ { group_id, user_id },
+ excludes
+ );
+ }
+
+ /**
+ * Find message group member relations by group ID
+ * @param {number|string} group_id - Message group ID
+ * @param {string[]} [excludes] - Fields to exclude from result
+ * @param {{name: string, direction?: 'asc'|'desc'}||null} [order_by] - Order by configuration
+ * @param {number} [limit=100] - Maximum number of records
+ * @param {number} [offset=0] - Number of records to skip
+ * @returns {Promise<MessageGroupMember[]>} Array of relations
+ */
+ static async find_by_group_id(group_id, excludes = [], order_by = null, limit = 100, offset = 0) {
+ return await new MessageGroupMember().find_many(
+ { group_id },
+ excludes,
+ order_by,
+ limit,
+ offset
+ );
+ }
+}
+
+module.exports = MessageGroupMember;
\ No newline at end of file
--- /dev/null
+/**
+ * @file Post model for phase.posts table
+ */
+
+const { Model, NotFoundError, ValidationError, FailedToCreateError } = require('./model');
+
+/**
+ * @typedef {Object} Post
+ * @property {number} id - Post ID (primary key)
+ * @property {number} user_id - User ID (foreign key)
+ * @property {string} title - Post title
+ * @property {string} content - Post content
+ * @property {string} post_type - Post type (e.g., 'blog', 'vlog')
+ * @property {string} visibility - Visibility (e.g., 'private', 'family', 'public')
+ * @property {number|null} created_by_id - ID of user who created this post
+ * @property {Date} created_at - Creation timestamp
+ * @property {boolean} is_deleted - Soft delete flag
+ * @property {number|null} deleted_by_id - ID of user who deleted this post
+ * @property {Date|null} deleted_at - Deletion timestamp
+ */
+
+/**
+ * Post model class
+ * @extends Model
+ */
+class Post extends Model {
+ /**
+ * Create a Post instance
+ * @param {Partial<Post>} [props] - Post properties
+ */
+ constructor(props) {
+ super(props);
+ this.table = 'phase.posts';
+ this.prepend = 'p';
+ this.default_columns = [
+ 'id', 'user_id', 'title', 'content', 'post_type', 'visibility',
+ 'created_by_id', 'created_at', 'is_deleted', 'deleted_by_id', 'deleted_at'
+ ];
+ this.update_exclude_columns = ['id', 'created_at', 'is_deleted', 'deleted_at', 'deleted_by_id'];
+ this.base_query = `
+ SELECT p.id, p.user_id, p.title, p.content, p.post_type, p.visibility,
+ p.created_by_id, p.created_at, p.is_deleted, p.deleted_by_id, p.deleted_at
+ FROM phase.posts p
+ WHERE p.is_deleted = false
+ `;
+ this.base_list_query = `
+ SELECT p.id, p.user_id, p.title, p.content, p.post_type, p.visibility,
+ p.created_by_id, p.created_at
+ FROM phase.posts p
+ WHERE p.is_deleted = false
+ `;
+ this.default_order_by = 'ORDER BY p.created_at DESC';
+ this.instance = _props => new Post(_props);
+ }
+
+ /**
+ * Create a new post
+ * @param {Omit<Post, 'id'|'created_at'|'is_deleted'|'deleted_by_id'|'deleted_at'>} post_data - Post data
+ * @returns {Promise<Post>} Created post instance
+ * @throws {ValidationError} If required fields are missing
+ * @throws {FailedToCreateError} If creation fails
+ */
+ static async create(post_data) {
+ const { user_id, title, content, post_type, visibility = 'private', created_by_id = null } = post_data;
+ if (!user_id || !title || !content || !post_type) {
+ throw new ValidationError('Missing required fields: user_id, title, content, post_type');
+ }
+ const query_str = `
+ INSERT INTO phase.posts (user_id, title, content, post_type, visibility, created_by_id)
+ VALUES ($1, $2, $3, $4, $5, $6) RETURNING *;
+ `;
+ const values = [user_id, title, content, post_type, visibility, created_by_id];
+ const result = await phsdb.query(query_str, values, { plain: true });
+ if (!result) throw new FailedToCreateError('Failed to create post');
+ return new Post(result);
+ }
+
+ /**
+ * Find post by title
+ * @param {string} title - Title to search for
+ * @param {string[]} [excludes] - Fields to exclude from result
+ * @returns {Promise<Post|null>} Post instance or null
+ */
+ static async find_by_title(title, excludes = []) {
+ return await new Post().find_one({ title }, excludes);
+ }
+
+ /**
+ * Soft delete post
+ * @param {number|string} deleted_by_id - ID of user performing deletion
+ * @returns {Promise<Post>} Updated post instance
+ * @throws {ValidationError} If deleted_by_id is invalid
+ * @throws {NotFoundError} If record not found
+ */
+ async soft_delete(deleted_by_id) {
+ const deleted_by_id_int = parseInt(deleted_by_id, 10);
+ if (isNaN(deleted_by_id_int)) {
+ throw new ValidationError('deleted_by_id must be a valid integer');
+ }
+ return await this.update({
+ is_deleted: true,
+ deleted_at: new Date().toISOString(),
+ deleted_by_id: deleted_by_id_int
+ });
+ }
+}
+
+module.exports = Post;
\ No newline at end of file
* @file User model for phase.users table
*/
-const { Model, ValidationError } = require( './model' );
+const db = require('../models');
+const bcrypt = require('bcrypt');
+const jwt = require('jsonwebtoken');
+const config = require('../config/default.json');
+const { Model, ValidationError } = require('./model');
+const createHttpError = require('http-errors');
/**
* @typedef {Object} User
* @extends Model
*/
class User extends Model {
- /**
- * Create a User instance
- * @param {Partial<User>} [props] - User properties
- */
- constructor( props ) {
- super( props );
+ constructor(props) {
+ super(props);
this.table = 'phase.users';
this.prepend = 'u';
this.default_columns = [
];
this.update_exclude_columns = ['id', 'created_at', 'is_deleted', 'deleted_at', 'deleted_by_id'];
this.base_query = `
- SELECT u.id,
- u.email,
- u.first_name,
- u.middle_name,
- u.last_name,
- u.initials,
- u.nickname,
- u.created_by_id,
- u.created_at,
- u.is_deleted,
- u.deleted_by_id,
- u.deleted_at,
- u.is_active,
- u.deactivated_by_id,
- u.deactivated_at
+ SELECT u.id, u.email, u.first_name, u.middle_name, u.last_name, u.initials, u.nickname,
+ u.created_by_id, u.created_at, u.is_deleted, u.deleted_by_id, u.deleted_at,
+ u.is_active, u.deactivated_by_id, u.deactivated_at
FROM phase.users u
WHERE u.is_deleted = false
`;
this.base_list_query = `
- SELECT u.id,
- u.email,
- u.first_name,
- u.middle_name,
- u.last_name,
- u.initials,
- u.nickname,
- u.created_by_id,
- u.created_at,
- u.is_active,
- u.deactivated_by_id,
- u.deactivated_at
+ SELECT u.id, u.email, u.first_name, u.middle_name, u.last_name, u.initials, u.nickname,
+ u.created_by_id, u.created_at, u.is_active, u.deactivated_by_id, u.deactivated_at
FROM phase.users u
WHERE u.is_deleted = false
`;
this.default_order_by = 'ORDER BY u.email ASC';
- this.instance = _props => new User( _props );
+ this.instance = _props => new User(_props);
}
- /**
- * Create a new user
- * @param {Omit<User, 'id'|'created_at'|'is_deleted'|'deleted_by_id'|'deleted_at'>} user_data - User data
- * @returns {Promise<User>} Created user instance
- * @throws {ValidationError} If required fields are missing
- */
- static async create( user_data ) {
+ static async create(user_data) {
const {
email, first_name, middle_name = '', last_name, initials = null, nickname = null,
created_by_id = null, is_active = true, deactivated_by_id = null, deactivated_at = null
} = user_data;
if (!email || !first_name || !last_name) {
- throw new ValidationError( 'Missing required fields: email, first_name, last_name' );
+ throw new ValidationError('Missing required fields: email, first_name, last_name');
}
const query_str = `
INSERT INTO phase.users (email, first_name, middle_name, last_name, initials, nickname, created_by_id,
email, first_name, middle_name, last_name, initials, nickname,
created_by_id, is_active, deactivated_by_id, deactivated_at
];
- const result = await phsdb.query( query_str, values, { plain:true } );
- if (!result) throw new ValidationError( 'Failed to create user' );
- return new User( result );
- };
+ const result = await phsdb.query(query_str, values, { plain: true });
+ if (!result) throw new ValidationError('Failed to create user');
+ return new User(result);
+ }
async get_user_roles() {
const query_str = `
- SELECT r.*
+ SELECT r.name
FROM phase.user_roles ur
- inner join phase.roles r on r.id = ur.role_id
- WHERE ur.user_id = $1 and r.is_deleted = false
+ INNER JOIN phase.roles r ON r.id = ur.role_id
+ WHERE ur.user_id = $1 AND r.is_deleted = false
`;
- return await phsdb.query( query_str, [this.id], { plain:true } );
- };
-
- /**
- * Find user by email
- * @param {string} email - Email to search for
- * @param {string[]} [excludes] - Fields to exclude from result
- * @returns {Promise<User|null>} User instance or null
- */
- static async find_by_email( email, excludes = [] ) {
- return await new User().find_one( { email }, excludes );
- }
-
- // noinspection JSUnusedGlobalSymbols
- /**
- * Find user by nickname
- * @param {string} nickname - Nickname to search for
- * @param {string[]} [excludes] - Fields to exclude from result
- * @returns {Promise<User|null>} User instance or null
- */
- static async find_by_nickname( nickname, excludes = [] ) {
- return await new User().find_one( { nickname }, excludes );
- }
-
- /**
- * Find active users
- * @param {string[]} [excludes] - Fields to exclude from result
- * @param {{name: string, direction?: 'asc'|'desc'}||null} [order_by] - Order by configuration
- * @param {number} [limit=100] - Maximum number of records
- * @param {number} [offset=0] - Number of records to skip
- * @returns {Promise<User[]>} Array of active users
- */
- static async find_active( excludes = [], order_by = null, limit = 100, offset = 0 ) {
- return await new User().find_many( { is_active:true }, excludes, order_by, limit, offset );
- };
-
- // noinspection JSUnusedGlobalSymbols
- /**
- * Find deleted users
- * @param {string[]} [excludes] - Fields to exclude from result
- * @param {{name: string, direction?: 'asc'|'desc'}||null} [order_by] - Order by configuration
- * @param {number} [limit=100] - Maximum number of records
- * @param {number} [offset=0] - Number of records to skip
- * @returns {Promise<User[]>} Array of deleted users
- */
- static async find_deleted( excludes = [], order_by = null, limit = 100, offset = 0 ) {
- const query_str = this.prototype.base_list_query.replace( 'WHERE u.is_deleted = false', 'WHERE u.is_deleted = true' );
+ const result = await phsdb.query(query_str, [this.id]);
+ return result.map(r => r.name);
+ }
+
+ static async find_by_email(email, excludes = []) {
+ return await new User().find_one({ email }, excludes);
+ }
+
+ static async find_by_nickname(nickname, excludes = []) {
+ return await new User().find_one({ nickname }, excludes);
+ }
+
+ static async find_active(excludes = [], order_by = null, limit = 100, offset = 0) {
+ return await new User().find_many({ is_active: true }, excludes, order_by, limit, offset);
+ }
+
+ static async find_deleted(excludes = [], order_by = null, limit = 100, offset = 0) {
+ const query_str = this.prototype.base_list_query.replace('WHERE u.is_deleted = false', 'WHERE u.is_deleted = true');
const instance = this.prototype.instance;
- const { keys, values } = this.prototype.build_where( {}, this.prototype.default_columns );
- values.push( limit, offset );
+ const { keys, values } = this.prototype.build_where({}, this.prototype.default_columns);
+ values.push(limit, offset);
const results = await phsdb.query(
`
- ${ query_str }
- ${ this.prototype.where_clause( keys, this.prototype.prepend ) }
- ${ order_by ? `ORDER BY ${ order_by.name } ${ order_by.direction ?? 'asc' }` : this.prototype.default_order_by ?? '' }
- LIMIT $${ values.length - 1 } OFFSET $${ values.length }
+ ${query_str}
+ ${this.prototype.where_clause(keys, this.prototype.prepend)}
+ ${order_by ? `ORDER BY ${order_by.name} ${order_by.direction ?? 'asc'}` : this.prototype.default_order_by ?? ''}
+ LIMIT $${values.length - 1} OFFSET $${values.length}
`,
values
);
- return results.map( result => {
- const found = instance( result );
- excludes?.forEach( e => delete found[e] );
+ return results.map(result => {
+ const found = instance(result);
+ excludes?.forEach(e => delete found[e]);
return found;
- } );
- }
-
- /**
- * Deactivate user
- * @param {number|string} deactivated_by_id - ID of user performing deactivation
- * @returns {Promise<User>} Updated user instance
- * @throws {ValidationError} If deactivated_by_id is invalid
- */
- async deactivate( deactivated_by_id ) {
- const deactivated_by_id_int = parseInt( deactivated_by_id, 10 );
- if (isNaN( deactivated_by_id_int )) {
- throw new ValidationError( 'deactivated_by_id must be a valid integer' );
+ });
+ }
+
+ async deactivate(deactivated_by_id) {
+ const deactivated_by_id_int = parseInt(deactivated_by_id, 10);
+ if (isNaN(deactivated_by_id_int)) {
+ throw new ValidationError('deactivated_by_id must be a valid integer');
}
- return await this.update( {
- is_active:false,
- deactivated_at:new Date().toISOString(),
- deactivated_by_id:deactivated_by_id_int
- } );
+ return await this.update({
+ is_active: false,
+ deactivated_at: new Date().toISOString(),
+ deactivated_by_id: deactivated_by_id_int
+ });
}
- /**
- * Reactivate user
- * @returns {Promise<User>} Updated user instance
- */
async reactivate() {
- return await this.update( {
- is_active:true,
- deactivated_at:null,
- deactivated_by_id:null
- } );
- }
-
- /**
- * Soft delete user
- * @param {number|string} deleted_by_id - ID of user performing deletion
- * @returns {Promise<User>} Updated user instance
- * @throws {ValidationError} If deleted_by_id is invalid
- */
- async soft_delete( deleted_by_id ) {
- const deleted_by_id_int = parseInt( deleted_by_id, 10 );
- if (isNaN( deleted_by_id_int )) {
- throw new ValidationError( 'deleted_by_id must be a valid integer' );
+ return await this.update({
+ is_active: true,
+ deactivated_at: null,
+ deactivated_by_id: null
+ });
+ }
+
+ async comparePassword(password) {
+ const auth = await db.authentication.find_by_user_id(this.id);
+ return auth ? bcrypt.compareSync(password, auth.password) : false;
+ }
+
+ async createToken() {
+ const auth = await db.authentication.find_by_user_id(this.id);
+ const roles = await this.get_user_roles();
+ const tokenPayload = { id: this.id, email: this.email, roles };
+ const token = jwt.sign(tokenPayload, config.keys.secret, { expiresIn: '24h' });
+ const { exp } = jwt.decode(token);
+ const token_expiry = new Date(exp * 1000).toISOString();
+ await auth.update({
+ password_failures_since_last_success: 0,
+ password_verification_token: token,
+ password_verification_token_expiry: token_expiry
+ });
+ return token;
+ }
+
+ async failLogin() {
+ const auth = await db.authentication.find_by_user_id(this.id);
+ await auth.update({
+ password_failures_since_last_success: (auth.password_failures_since_last_success || 0) + 1,
+ password_verification_token: null,
+ password_verification_token_expiry: null,
+ last_password_failure: new Date().toISOString()
+ });
+ return true;
+ }
+
+ async lockAccount() {
+ const auth = await db.authentication.find_by_user_id(this.id);
+ await auth.update({
+ is_locked: true,
+ locked_date: new Date().toISOString()
+ });
+ return true;
+ }
+
+ async hashPassword(password) {
+ const auth = await db.authentication.find_by_user_id(this.id);
+ if (!auth) throw createHttpError(400, 'No authentication record found for this user.');
+ const salt = await bcrypt.genSalt(10);
+ const hash = await bcrypt.hash(password, salt);
+ await auth.update({
+ password_failures_since_last_success: 0,
+ password_changed_date: new Date().toISOString(),
+ password: hash,
+ password_salt: salt,
+ ms_password: false,
+ password_reset_token: null,
+ password_reset_expire_date: null
+ });
+ return { salt, hash };
+ }
+
+ async soft_delete(deleted_by_id) {
+ const deleted_by_id_int = parseInt(deleted_by_id, 10);
+ if (isNaN(deleted_by_id_int)) {
+ throw new ValidationError('deleted_by_id must be a valid integer');
}
- return await this.update( {
- is_deleted:true,
- deleted_at:new Date().toISOString(),
- deleted_by_id:deleted_by_id_int
- } );
+ return await this.update({
+ is_deleted: true,
+ deleted_at: new Date().toISOString(),
+ deleted_by_id: deleted_by_id_int
+ });
}
- /**
- * Check if user is active
- * @returns {boolean} True if user is active
- */
is_active() {
return this.is_active === true;
}
- // noinspection JSUnusedGlobalSymbols
- /**
- * Get user data without sensitive information
- * @returns {Omit<User, 'password'>} User data
- */
to_safe_json() {
const { password, ...safe_data } = this.toJSON();
- // noinspection JSValidateTypes
return safe_data;
}
}
const express = require('express');
const router = express.Router();
-const { validateAuth } = require('../middleware/routeHelpers');
const authController = require('../controllers/auth.controller');
-module.exports = (passport) => {
+module.exports = () => {
router.post('/login', authController.login);
return router;
};
\ No newline at end of file
--- /dev/null
+/**
+ * @file Media routes configuration
+ */
+
+const express = require('express');
+const router = express.Router();
+const { validateAuth } = require('../middleware/routeHelpers');
+const media_controller = require('../controllers/media.controller');
+
+/**
+ * Configure media routes
+ * @param {Object} passport - Passport instance for authentication
+ * @returns {Object} Express router with media routes
+ */
+module.exports = (passport) => {
+ router.post('/create', validateAuth(passport), media_controller.create);
+ router.get('/file_path/:file_path', validateAuth(passport), media_controller.find_by_file_path);
+ router.get('/:id', validateAuth(passport), media_controller.find_one);
+ router.get('/', validateAuth(passport), media_controller.find_many);
+ router.put('/:id', validateAuth(passport), media_controller.update);
+ router.put('/:id/soft_delete', validateAuth(passport), media_controller.soft_delete);
+ return router;
+};
\ No newline at end of file
--- /dev/null
+/**
+ * @file Message routes configuration
+ */
+
+const express = require('express');
+const router = express.Router();
+const { validateAuth } = require('../middleware/routeHelpers');
+const message_controller = require('../controllers/message.controller');
+
+/**
+ * Configure message routes
+ * @param {Object} passport - Passport instance for authentication
+ * @returns {Object} Express router with message routes
+ */
+module.exports = (passport) => {
+ router.post('/create', validateAuth(passport), message_controller.create);
+ router.get('/group/:group_id', validateAuth(passport), message_controller.find_by_group_id);
+ router.get('/recipient/:recipient_id', validateAuth(passport), message_controller.find_by_recipient_id);
+ router.get('/:id', validateAuth(passport), message_controller.find_one);
+ router.get('/', validateAuth(passport), message_controller.find_many);
+ router.put('/:id/mark_as_read', validateAuth(passport), message_controller.mark_as_read);
+ return router;
+};
\ No newline at end of file
--- /dev/null
+/**
+ * @file Message group routes configuration
+ */
+
+const express = require('express');
+const router = express.Router();
+const { validateAuth } = require('../middleware/routeHelpers');
+const message_group_controller = require('../controllers/message_group.controller');
+
+/**
+ * Configure message group routes
+ * @param {Object} passport - Passport instance for authentication
+ * @returns {Object} Express router with message group routes
+ */
+module.exports = (passport) => {
+ router.post('/create', validateAuth(passport), message_group_controller.create);
+ router.get('/:id', validateAuth(passport), message_group_controller.find_one);
+ router.get('/', validateAuth(passport), message_group_controller.find_many);
+ router.put('/:id', validateAuth(passport), message_group_controller.update);
+ return router;
+};
\ No newline at end of file
--- /dev/null
+/**
+ * @file Message group members routes configuration
+ */
+
+const express = require('express');
+const router = express.Router();
+const { validateAuth } = require('../middleware/routeHelpers');
+const message_group_members_controller = require('../controllers/message_group_members.controller');
+
+/**
+ * Configure message group members routes
+ * @param {Object} passport - Passport instance for authentication
+ * @returns {Object} Express router with message group members routes
+ */
+module.exports = (passport) => {
+ router.post('/add', validateAuth(passport), message_group_members_controller.add_relation);
+ router.delete('/remove', validateAuth(passport), message_group_members_controller.remove_relation);
+ router.get('/ids/:group_id/:user_id', validateAuth(passport), message_group_members_controller.find_by_ids);
+ router.get('/group/:group_id', validateAuth(passport), message_group_members_controller.find_by_group_id);
+ return router;
+};
\ No newline at end of file
--- /dev/null
+/**
+ * @file Post routes configuration
+ */
+
+const express = require('express');
+const router = express.Router();
+const { validateAuth } = require('../middleware/routeHelpers');
+const post_controller = require('../controllers/post.controller');
+
+/**
+ * Configure post routes
+ * @param {Object} passport - Passport instance for authentication
+ * @returns {Object} Express router with post routes
+ */
+module.exports = (passport) => {
+ router.post('/create', validateAuth(passport), post_controller.create);
+ router.get('/title/:title', validateAuth(passport), post_controller.find_by_title);
+ router.get('/:id', validateAuth(passport), post_controller.find_one);
+ router.get('/', validateAuth(passport), post_controller.find_many);
+ router.put('/:id', validateAuth(passport), post_controller.update);
+ router.put('/:id/soft_delete', validateAuth(passport), post_controller.soft_delete);
+ return router;
+};
\ No newline at end of file