dev-prettier #4
1
.husky/.gitignore
vendored
Normal file
1
.husky/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
_
|
4
.husky/pre-commit
Executable file
4
.husky/pre-commit
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
npx lint-staged
|
9
.prettierrc.json
Normal file
9
.prettierrc.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"tabWidth": 4,
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 120,
|
||||||
|
"quoteProps": "as-needed",
|
||||||
|
"arrowParens": "avoid"
|
||||||
|
}
|
40
index.ts
40
index.ts
@ -1,33 +1,33 @@
|
|||||||
import { app } from "./app";
|
import { app } from './app';
|
||||||
import { logger } from "./logger";
|
import { logger } from './logger';
|
||||||
|
|
||||||
const port = app.get("port");
|
const port = app.get('port');
|
||||||
const host = app.get("host");
|
const host = app.get('host');
|
||||||
const server = app.listen(port);
|
const server = app.listen(port);
|
||||||
|
|
||||||
app.listen(port).then(() => {
|
app.listen(port).then(() => {
|
||||||
logger.info(`Walias app listening on http://${host}:${port}`);
|
logger.info(`Walias app listening on http://${host}:${port}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on("SIGINT", () => {
|
process.on('SIGINT', () => {
|
||||||
logger.info("Received SIGINT signal. Shutting down gracefully.");
|
logger.info('Received SIGINT signal. Shutting down gracefully.');
|
||||||
|
|
||||||
server.close(() => {
|
server.close(() => {
|
||||||
logger.info("HTTP server closed.");
|
logger.info('HTTP server closed.');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on("SIGTERM", () => {
|
process.on('SIGTERM', () => {
|
||||||
logger.info("Received SIGTERM signal. Shutting down gracefully.");
|
logger.info('Received SIGTERM signal. Shutting down gracefully.');
|
||||||
|
|
||||||
server.close(() => {
|
server.close(() => {
|
||||||
logger.info("HTTP server closed.");
|
logger.info('HTTP server closed.');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on("unhandledRejection", (reason) => {
|
process.on('unhandledRejection', reason => {
|
||||||
logger.error("Unhandled rejection", reason);
|
logger.error('Unhandled rejection', reason);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
10
logger.ts
10
logger.ts
@ -1,10 +1,10 @@
|
|||||||
// For more information about this file see https://dove.feathersjs.com/guides/cli/logging.html
|
// For more information about this file see https://dove.feathersjs.com/guides/cli/logging.html
|
||||||
import { createLogger, format, transports } from "winston";
|
import { createLogger, format, transports } from 'winston';
|
||||||
|
|
||||||
// Configure the Winston logger. For the complete documentation see https://github.com/winstonjs/winston
|
// Configure the Winston logger. For the complete documentation see https://github.com/winstonjs/winston
|
||||||
export const logger = createLogger({
|
export const logger = createLogger({
|
||||||
// To see more detailed errors, change this to 'debug'
|
// To see more detailed errors, change this to 'debug'
|
||||||
level: "info",
|
level: 'info',
|
||||||
format: format.combine(format.splat(), format.simple()),
|
format: format.combine(format.splat(), format.simple()),
|
||||||
transports: [new transports.Console()],
|
transports: [new transports.Console()],
|
||||||
});
|
});
|
||||||
|
556
package-lock.json
generated
556
package-lock.json
generated
@ -35,6 +35,8 @@
|
|||||||
"@types/mocha": "^10.0.1",
|
"@types/mocha": "^10.0.1",
|
||||||
"@types/node": "^20.4.5",
|
"@types/node": "^20.4.5",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
|
"husky": "^8.0.3",
|
||||||
|
"lint-staged": "^13.2.3",
|
||||||
"mocha": "^10.2.0",
|
"mocha": "^10.2.0",
|
||||||
"nodemon": "^3.0.1",
|
"nodemon": "^3.0.1",
|
||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
@ -705,6 +707,19 @@
|
|||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/aggregate-error": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"clean-stack": "^2.0.0",
|
||||||
|
"indent-string": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ajv": {
|
"node_modules/ajv": {
|
||||||
"version": "8.12.0",
|
"version": "8.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||||
@ -832,6 +847,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/astral-regex": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/async": {
|
"node_modules/async": {
|
||||||
"version": "3.2.4",
|
"version": "3.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
|
||||||
@ -1074,6 +1098,15 @@
|
|||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/clean-stack": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cli-cursor": {
|
"node_modules/cli-cursor": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
|
||||||
@ -1098,6 +1131,72 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cli-truncate": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"slice-ansi": "^5.0.0",
|
||||||
|
"string-width": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cli-truncate/node_modules/ansi-regex": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cli-truncate/node_modules/emoji-regex": {
|
||||||
|
"version": "9.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
|
||||||
|
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/cli-truncate/node_modules/string-width": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"eastasianwidth": "^0.2.0",
|
||||||
|
"emoji-regex": "^9.2.2",
|
||||||
|
"strip-ansi": "^7.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cli-truncate/node_modules/strip-ansi": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": "^6.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cli-width": {
|
"node_modules/cli-width": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
|
||||||
@ -1161,6 +1260,12 @@
|
|||||||
"simple-swizzle": "^0.2.2"
|
"simple-swizzle": "^0.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/colorette": {
|
||||||
|
"version": "2.0.20",
|
||||||
|
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
|
||||||
|
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/colorspace": {
|
"node_modules/colorspace": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz",
|
||||||
@ -1422,6 +1527,12 @@
|
|||||||
"node": ">=0.3.1"
|
"node": ">=0.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eastasianwidth": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/ecdsa-sig-formatter": {
|
"node_modules/ecdsa-sig-formatter": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||||
@ -1550,6 +1661,68 @@
|
|||||||
"node": ">=0.8.x"
|
"node": ">=0.8.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/execa": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"cross-spawn": "^7.0.3",
|
||||||
|
"get-stream": "^6.0.1",
|
||||||
|
"human-signals": "^4.3.0",
|
||||||
|
"is-stream": "^3.0.0",
|
||||||
|
"merge-stream": "^2.0.0",
|
||||||
|
"npm-run-path": "^5.1.0",
|
||||||
|
"onetime": "^6.0.0",
|
||||||
|
"signal-exit": "^3.0.7",
|
||||||
|
"strip-final-newline": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.18.0 || ^16.14.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/execa/node_modules/is-stream": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/execa/node_modules/mimic-fn": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/execa/node_modules/onetime": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"mimic-fn": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/express": {
|
"node_modules/express": {
|
||||||
"version": "4.18.2",
|
"version": "4.18.2",
|
||||||
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
|
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
|
||||||
@ -1849,6 +2022,18 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/get-stream": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/glob": {
|
"node_modules/glob": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
|
||||||
@ -1969,6 +2154,30 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/human-signals": {
|
||||||
|
"version": "4.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz",
|
||||||
|
"integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.18.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/husky": {
|
||||||
|
"version": "8.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz",
|
||||||
|
"integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"husky": "lib/bin.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/typicode"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/iconv-lite": {
|
"node_modules/iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
@ -2006,6 +2215,15 @@
|
|||||||
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
|
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/indent-string": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/inflight": {
|
"node_modules/inflight": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||||
@ -2272,6 +2490,146 @@
|
|||||||
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
|
||||||
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="
|
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="
|
||||||
},
|
},
|
||||||
|
"node_modules/lilconfig": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lint-staged": {
|
||||||
|
"version": "13.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-13.2.3.tgz",
|
||||||
|
"integrity": "sha512-zVVEXLuQIhr1Y7R7YAWx4TZLdvuzk7DnmrsTNL0fax6Z3jrpFcas+vKbzxhhvp6TA55m1SQuWkpzI1qbfDZbAg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": "5.2.0",
|
||||||
|
"cli-truncate": "^3.1.0",
|
||||||
|
"commander": "^10.0.0",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"execa": "^7.0.0",
|
||||||
|
"lilconfig": "2.1.0",
|
||||||
|
"listr2": "^5.0.7",
|
||||||
|
"micromatch": "^4.0.5",
|
||||||
|
"normalize-path": "^3.0.0",
|
||||||
|
"object-inspect": "^1.12.3",
|
||||||
|
"pidtree": "^0.6.0",
|
||||||
|
"string-argv": "^0.3.1",
|
||||||
|
"yaml": "^2.2.2"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"lint-staged": "bin/lint-staged.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.13.1 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/lint-staged"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lint-staged/node_modules/chalk": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lint-staged/node_modules/commander": {
|
||||||
|
"version": "10.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
|
||||||
|
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lint-staged/node_modules/debug": {
|
||||||
|
"version": "4.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
|
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lint-staged/node_modules/ms": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/listr2": {
|
||||||
|
"version": "5.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/listr2/-/listr2-5.0.8.tgz",
|
||||||
|
"integrity": "sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"cli-truncate": "^2.1.0",
|
||||||
|
"colorette": "^2.0.19",
|
||||||
|
"log-update": "^4.0.0",
|
||||||
|
"p-map": "^4.0.0",
|
||||||
|
"rfdc": "^1.3.0",
|
||||||
|
"rxjs": "^7.8.0",
|
||||||
|
"through": "^2.3.8",
|
||||||
|
"wrap-ansi": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^14.13.1 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"enquirer": ">= 2.3.0 < 3"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"enquirer": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/listr2/node_modules/cli-truncate": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"slice-ansi": "^3.0.0",
|
||||||
|
"string-width": "^4.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/listr2/node_modules/slice-ansi": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^4.0.0",
|
||||||
|
"astral-regex": "^2.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/locate-path": {
|
"node_modules/locate-path": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||||
@ -2308,6 +2666,55 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/log-update": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-escapes": "^4.3.0",
|
||||||
|
"cli-cursor": "^3.1.0",
|
||||||
|
"slice-ansi": "^4.0.0",
|
||||||
|
"wrap-ansi": "^6.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/log-update/node_modules/slice-ansi": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^4.0.0",
|
||||||
|
"astral-regex": "^2.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/log-update/node_modules/wrap-ansi": {
|
||||||
|
"version": "6.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
||||||
|
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^4.0.0",
|
||||||
|
"string-width": "^4.1.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/logform": {
|
"node_modules/logform": {
|
||||||
"version": "2.5.1",
|
"version": "2.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz",
|
||||||
@ -2361,6 +2768,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
|
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
|
||||||
},
|
},
|
||||||
|
"node_modules/merge-stream": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/methods": {
|
"node_modules/methods": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||||
@ -2369,6 +2782,19 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/micromatch": {
|
||||||
|
"version": "4.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
||||||
|
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"braces": "^3.0.2",
|
||||||
|
"picomatch": "^2.3.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mime": {
|
"node_modules/mime": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||||
@ -2695,6 +3121,33 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/npm-run-path": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"path-key": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/npm-run-path/node_modules/path-key": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/object-assign": {
|
"node_modules/object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
@ -2854,6 +3307,21 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/p-map": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"aggregate-error": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/parseurl": {
|
"node_modules/parseurl": {
|
||||||
"version": "1.3.3",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||||
@ -2912,6 +3380,18 @@
|
|||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pidtree": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"pidtree": "bin/pidtree.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/prettier": {
|
"node_modules/prettier": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz",
|
||||||
@ -3108,6 +3588,12 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/rfdc": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/run-async": {
|
"node_modules/run-async": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
|
||||||
@ -3307,6 +3793,46 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/slice-ansi": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": "^6.0.0",
|
||||||
|
"is-fullwidth-code-point": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/slice-ansi/node_modules/ansi-styles": {
|
||||||
|
"version": "6.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
|
||||||
|
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/slice-ansi/node_modules/is-fullwidth-code-point": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/socket.io": {
|
"node_modules/socket.io": {
|
||||||
"version": "4.7.1",
|
"version": "4.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.1.tgz",
|
||||||
@ -3429,6 +3955,15 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/string-argv": {
|
||||||
|
"version": "0.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
|
||||||
|
"integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6.19"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/string-width": {
|
"node_modules/string-width": {
|
||||||
"version": "4.2.3",
|
"version": "4.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||||
@ -3455,6 +3990,18 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/strip-final-newline": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/strip-json-comments": {
|
"node_modules/strip-json-comments": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
||||||
@ -3843,6 +4390,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||||
},
|
},
|
||||||
|
"node_modules/yaml": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/yargs": {
|
"node_modules/yargs": {
|
||||||
"version": "17.7.2",
|
"version": "17.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||||
|
@ -68,11 +68,16 @@
|
|||||||
"@types/mocha": "^10.0.1",
|
"@types/mocha": "^10.0.1",
|
||||||
"@types/node": "^20.4.5",
|
"@types/node": "^20.4.5",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
|
"husky": "^8.0.3",
|
||||||
|
"lint-staged": "^13.2.3",
|
||||||
"mocha": "^10.2.0",
|
"mocha": "^10.2.0",
|
||||||
"nodemon": "^3.0.1",
|
"nodemon": "^3.0.1",
|
||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
"shx": "^0.3.4",
|
"shx": "^0.3.4",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^5.1.6"
|
"typescript": "^5.1.6"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*.{ts,js,css,md}": "prettier --write"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
88
src/app.ts
88
src/app.ts
@ -1,25 +1,17 @@
|
|||||||
import { feathers } from "@feathersjs/feathers";
|
import { feathers } from '@feathersjs/feathers';
|
||||||
import express, {
|
import express, { rest, json, urlencoded, cors, serveStatic, notFound, errorHandler } from '@feathersjs/express';
|
||||||
rest,
|
import configuration from '@feathersjs/configuration';
|
||||||
json,
|
import socketio from '@feathersjs/socketio';
|
||||||
urlencoded,
|
import session from 'express-session';
|
||||||
cors,
|
import cookieParser from 'cookie-parser';
|
||||||
serveStatic,
|
|
||||||
notFound,
|
|
||||||
errorHandler,
|
|
||||||
} from "@feathersjs/express";
|
|
||||||
import configuration from "@feathersjs/configuration";
|
|
||||||
import socketio from "@feathersjs/socketio";
|
|
||||||
import session from "express-session";
|
|
||||||
import cookieParser from "cookie-parser";
|
|
||||||
|
|
||||||
import type { Application } from "./declarations";
|
import type { Application } from './declarations';
|
||||||
|
|
||||||
import { logger } from "./logger";
|
import { logger } from './logger';
|
||||||
import { logError } from "./hooks/log-error";
|
import { logError } from './hooks/log-error';
|
||||||
import { services } from "./services/index";
|
import { services } from './services/index';
|
||||||
import { channels } from "./channels";
|
import { channels } from './channels';
|
||||||
import { randomUUID } from "crypto";
|
import { randomUUID } from 'crypto';
|
||||||
|
|
||||||
const app: Application = express(feathers());
|
const app: Application = express(feathers());
|
||||||
|
|
||||||
@ -27,42 +19,42 @@ const app: Application = express(feathers());
|
|||||||
app.configure(configuration());
|
app.configure(configuration());
|
||||||
app.use(cors());
|
app.use(cors());
|
||||||
app.use(
|
app.use(
|
||||||
json({
|
json({
|
||||||
limit: "20mb",
|
limit: '20mb',
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
app.use(
|
app.use(
|
||||||
session({
|
session({
|
||||||
secret: randomUUID(),
|
secret: randomUUID(),
|
||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: true,
|
saveUninitialized: true,
|
||||||
cookie: { secure: false },
|
cookie: { secure: false },
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// Propagate session to request.params in feathers services
|
// Propagate session to request.params in feathers services
|
||||||
app.use(function (req, _res, next) {
|
app.use(function (req, _res, next) {
|
||||||
req.feathers = {
|
req.feathers = {
|
||||||
...req.feathers,
|
...req.feathers,
|
||||||
session: req.session,
|
session: req.session,
|
||||||
};
|
};
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(urlencoded({ extended: true }));
|
app.use(urlencoded({ extended: true }));
|
||||||
// Host the public folder
|
// Host the public folder
|
||||||
app.use("/", serveStatic(app.get("public")));
|
app.use('/', serveStatic(app.get('public')));
|
||||||
|
|
||||||
// Configure services and real-time functionality
|
// Configure services and real-time functionality
|
||||||
app.configure(rest());
|
app.configure(rest());
|
||||||
app.configure(
|
app.configure(
|
||||||
socketio({
|
socketio({
|
||||||
cors: {
|
cors: {
|
||||||
origin: app.get("origins"),
|
origin: app.get('origins'),
|
||||||
},
|
},
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
app.configure(services);
|
app.configure(services);
|
||||||
app.configure(channels);
|
app.configure(channels);
|
||||||
@ -73,17 +65,17 @@ app.use(errorHandler({ logger }));
|
|||||||
|
|
||||||
// Register hooks that run on all service methods
|
// Register hooks that run on all service methods
|
||||||
app.hooks({
|
app.hooks({
|
||||||
around: {
|
around: {
|
||||||
all: [logError],
|
all: [logError],
|
||||||
},
|
},
|
||||||
before: {},
|
before: {},
|
||||||
after: {},
|
after: {},
|
||||||
error: {},
|
error: {},
|
||||||
});
|
});
|
||||||
// Register application setup and teardown hooks here
|
// Register application setup and teardown hooks here
|
||||||
app.hooks({
|
app.hooks({
|
||||||
setup: [],
|
setup: [],
|
||||||
teardown: [],
|
teardown: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
export { app };
|
export { app };
|
||||||
|
@ -1,41 +1,38 @@
|
|||||||
// For more information about this file see https://dove.feathersjs.com/guides/cli/channels.html
|
// For more information about this file see https://dove.feathersjs.com/guides/cli/channels.html
|
||||||
import type { RealTimeConnection, Params } from "@feathersjs/feathers";
|
import type { RealTimeConnection, Params } from '@feathersjs/feathers';
|
||||||
import type { AuthenticationResult } from "@feathersjs/authentication";
|
import type { AuthenticationResult } from '@feathersjs/authentication';
|
||||||
import "@feathersjs/transport-commons";
|
import '@feathersjs/transport-commons';
|
||||||
import type { Application, HookContext } from "./declarations";
|
import type { Application, HookContext } from './declarations';
|
||||||
import { logger } from "./logger";
|
import { logger } from './logger';
|
||||||
|
|
||||||
export const channels = (app: Application) => {
|
export const channels = (app: Application) => {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"Publishing all events to all authenticated users. See `channels.ts` and https://dove.feathersjs.com/api/channels.html for more information.",
|
'Publishing all events to all authenticated users. See `channels.ts` and https://dove.feathersjs.com/api/channels.html for more information.'
|
||||||
);
|
);
|
||||||
|
|
||||||
app.on("connection", (connection: RealTimeConnection) => {
|
app.on('connection', (connection: RealTimeConnection) => {
|
||||||
// On a new real-time connection, add it to the anonymous channel
|
// On a new real-time connection, add it to the anonymous channel
|
||||||
app.channel("anonymous").join(connection);
|
app.channel('anonymous').join(connection);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on(
|
app.on('login', (authResult: AuthenticationResult, { connection }: Params) => {
|
||||||
"login",
|
// connection can be undefined if there is no
|
||||||
(authResult: AuthenticationResult, { connection }: Params) => {
|
// real-time connection, e.g. when logging in via REST
|
||||||
// connection can be undefined if there is no
|
if (connection) {
|
||||||
// real-time connection, e.g. when logging in via REST
|
// The connection is no longer anonymous, remove it
|
||||||
if (connection) {
|
app.channel('anonymous').leave(connection);
|
||||||
// The connection is no longer anonymous, remove it
|
|
||||||
app.channel("anonymous").leave(connection);
|
|
||||||
|
|
||||||
// Add it to the authenticated user channel
|
// Add it to the authenticated user channel
|
||||||
app.channel("authenticated").join(connection);
|
app.channel('authenticated').join(connection);
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
app.publish((data: any, context: HookContext) => {
|
app.publish((data: any, context: HookContext) => {
|
||||||
// Here you can add event publishers to channels set up in `channels.js`
|
// Here you can add event publishers to channels set up in `channels.js`
|
||||||
// To publish only for a specific event use `app.publish(eventname, () => {})`
|
// To publish only for a specific event use `app.publish(eventname, () => {})`
|
||||||
|
|
||||||
// e.g. to publish all service events to all authenticated users use
|
// e.g. to publish all service events to all authenticated users use
|
||||||
return app.channel("authenticated");
|
return app.channel('authenticated');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import config from "config";
|
import config from 'config';
|
||||||
|
|
||||||
const wildDuckClient = axios.create({
|
const wildDuckClient = axios.create({
|
||||||
baseURL: config.get("wildDuck.url"),
|
baseURL: config.get('wildDuck.url'),
|
||||||
headers: {
|
headers: {
|
||||||
"X-Access-Token": config.get("wildDuck.token"),
|
'X-Access-Token': config.get('wildDuck.token'),
|
||||||
},
|
},
|
||||||
responseType: "json",
|
responseType: 'json',
|
||||||
});
|
});
|
||||||
|
|
||||||
export default wildDuckClient;
|
export default wildDuckClient;
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
// For more information about this file see https://dove.feathersjs.com/guides/cli/typescript.html
|
// For more information about this file see https://dove.feathersjs.com/guides/cli/typescript.html
|
||||||
import {
|
import { HookContext as FeathersHookContext, NextFunction } from '@feathersjs/feathers';
|
||||||
HookContext as FeathersHookContext,
|
import { Application as FeathersApplication } from '@feathersjs/express';
|
||||||
NextFunction,
|
|
||||||
} from "@feathersjs/feathers";
|
|
||||||
import { Application as FeathersApplication } from "@feathersjs/express";
|
|
||||||
type ApplicationConfiguration = any;
|
type ApplicationConfiguration = any;
|
||||||
|
|
||||||
export { NextFunction };
|
export { NextFunction };
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import type { HookContext, NextFunction } from "../declarations";
|
import type { HookContext, NextFunction } from '../declarations';
|
||||||
import { logger } from "../logger";
|
import { logger } from '../logger';
|
||||||
|
|
||||||
export const logError = async (context: HookContext, next: NextFunction) => {
|
export const logError = async (context: HookContext, next: NextFunction) => {
|
||||||
try {
|
try {
|
||||||
await next();
|
await next();
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
logger.error(error.stack);
|
logger.error(error.stack);
|
||||||
|
|
||||||
// Log validation errors
|
// Log validation errors
|
||||||
if (error.data) {
|
if (error.data) {
|
||||||
logger.error("Data: %O", error.data);
|
logger.error('Data: %O', error.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { NotAuthenticated } from "@feathersjs/errors";
|
import { NotAuthenticated } from '@feathersjs/errors';
|
||||||
import type { HookContext, NextFunction } from "../declarations";
|
import type { HookContext, NextFunction } from '../declarations';
|
||||||
|
|
||||||
// Check if user is stored in session
|
// Check if user is stored in session
|
||||||
export const validateAuth = async (context: HookContext) => {
|
export const validateAuth = async (context: HookContext) => {
|
||||||
if (!context.params.session?.user) {
|
if (!context.params.session?.user) {
|
||||||
throw new NotAuthenticated("Not authenticated");
|
throw new NotAuthenticated('Not authenticated');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
14
src/index.ts
14
src/index.ts
@ -1,13 +1,11 @@
|
|||||||
import { app } from "./app";
|
import { app } from './app';
|
||||||
import { logger } from "./logger";
|
import { logger } from './logger';
|
||||||
|
|
||||||
const port = app.get("port");
|
const port = app.get('port');
|
||||||
const host = app.get("host");
|
const host = app.get('host');
|
||||||
|
|
||||||
process.on("unhandledRejection", (reason) =>
|
process.on('unhandledRejection', reason => logger.error('Unhandled Rejection %O', reason));
|
||||||
logger.error("Unhandled Rejection %O", reason),
|
|
||||||
);
|
|
||||||
|
|
||||||
app.listen(port).then(() => {
|
app.listen(port).then(() => {
|
||||||
logger.info(`Feathers app listening on http://${host}:${port}`);
|
logger.info(`Feathers app listening on http://${host}:${port}`);
|
||||||
});
|
});
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
// For more information about this file see https://dove.feathersjs.com/guides/cli/logging.html
|
// For more information about this file see https://dove.feathersjs.com/guides/cli/logging.html
|
||||||
import { createLogger, format, transports } from "winston";
|
import { createLogger, format, transports } from 'winston';
|
||||||
|
|
||||||
// Configure the Winston logger. For the complete documentation see https://github.com/winstonjs/winston
|
// Configure the Winston logger. For the complete documentation see https://github.com/winstonjs/winston
|
||||||
export const logger = createLogger({
|
export const logger = createLogger({
|
||||||
// To see more detailed errors, change this to 'debug'
|
// To see more detailed errors, change this to 'debug'
|
||||||
level: "info",
|
level: 'info',
|
||||||
format: format.combine(format.splat(), format.simple()),
|
format: format.combine(format.splat(), format.simple()),
|
||||||
transports: [new transports.Console()],
|
transports: [new transports.Console()],
|
||||||
});
|
});
|
||||||
|
@ -1,33 +1,29 @@
|
|||||||
import type {
|
import type { NullableId, Params, ServiceInterface } from '@feathersjs/feathers';
|
||||||
NullableId,
|
|
||||||
Params,
|
|
||||||
ServiceInterface,
|
|
||||||
} from "@feathersjs/feathers";
|
|
||||||
|
|
||||||
import type { Application } from "../../declarations";
|
import type { Application } from '../../declarations';
|
||||||
import wildDuckClient from "../../clients/wildduck.client";
|
import wildDuckClient from '../../clients/wildduck.client';
|
||||||
import { faker } from "@faker-js/faker";
|
import { faker } from '@faker-js/faker';
|
||||||
import { BadRequest } from "@feathersjs/errors";
|
import { BadRequest } from '@feathersjs/errors';
|
||||||
import config from "config";
|
import config from 'config';
|
||||||
|
|
||||||
interface Alias {
|
interface Alias {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
id: string;
|
id: string;
|
||||||
address: string;
|
address: string;
|
||||||
main: boolean;
|
main: boolean;
|
||||||
user: string;
|
user: string;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
created: string;
|
created: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GetAddressInfoResponse {
|
interface GetAddressInfoResponse {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
results: Alias[];
|
results: Alias[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CreateAddressResponse {
|
interface CreateAddressResponse {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type AliasesData = any;
|
type AliasesData = any;
|
||||||
@ -37,102 +33,85 @@ type AliasesQuery = any;
|
|||||||
export type { Alias as Aliases, AliasesData, AliasesPatch, AliasesQuery };
|
export type { Alias as Aliases, AliasesData, AliasesPatch, AliasesQuery };
|
||||||
|
|
||||||
export interface AliasesServiceOptions {
|
export interface AliasesServiceOptions {
|
||||||
app: Application;
|
app: Application;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AliasesParams extends Params<AliasesQuery> {
|
export interface AliasesParams extends Params<AliasesQuery> {
|
||||||
session?: any;
|
session?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AliasesService<ServiceParams extends AliasesParams = AliasesParams>
|
export class AliasesService<ServiceParams extends AliasesParams = AliasesParams>
|
||||||
implements ServiceInterface<Alias, AliasesData, ServiceParams, AliasesPatch>
|
implements ServiceInterface<Alias, AliasesData, ServiceParams, AliasesPatch>
|
||||||
{
|
{
|
||||||
constructor(public options: AliasesServiceOptions) {}
|
constructor(public options: AliasesServiceOptions) {}
|
||||||
|
|
||||||
async find(params: ServiceParams): Promise<Alias[]> {
|
async find(params: ServiceParams): Promise<Alias[]> {
|
||||||
const userId = await this.getUserIdByEmailAddress(params);
|
const userId = await this.getUserIdByEmailAddress(params);
|
||||||
|
|
||||||
return this.getUserAddresses(userId);
|
return this.getUserAddresses(userId);
|
||||||
}
|
|
||||||
|
|
||||||
async create(data: AliasesData, params: ServiceParams): Promise<Alias>;
|
|
||||||
async create(
|
|
||||||
data: AliasesData,
|
|
||||||
params: ServiceParams,
|
|
||||||
): Promise<Alias | Alias[]> {
|
|
||||||
const userId = await this.getUserIdByEmailAddress(params);
|
|
||||||
|
|
||||||
const randomString = faker.git.commitSha({ length: 4 });
|
|
||||||
|
|
||||||
// Replace all non-alphanumeric characters with nothing and spaces with dashes
|
|
||||||
const alias =
|
|
||||||
`${faker.color.human()}-${faker.animal.snake()}-${randomString}`
|
|
||||||
.replace(/\s+/g, "-")
|
|
||||||
.replace(/[^a-zA-Z0-9-]/g, "")
|
|
||||||
.toLowerCase();
|
|
||||||
|
|
||||||
const emailDomain = config.get("wildDuck.domain");
|
|
||||||
|
|
||||||
const createResult = await wildDuckClient.post<CreateAddressResponse>(
|
|
||||||
`/users/${userId}/addresses`,
|
|
||||||
{
|
|
||||||
address: `${alias}@${emailDomain}`,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!createResult.data.success) {
|
|
||||||
throw new BadRequest("Failed to create alias");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.getUserAddresses(userId);
|
async create(data: AliasesData, params: ServiceParams): Promise<Alias>;
|
||||||
}
|
async create(data: AliasesData, params: ServiceParams): Promise<Alias | Alias[]> {
|
||||||
|
const userId = await this.getUserIdByEmailAddress(params);
|
||||||
|
|
||||||
private async getUserIdByEmailAddress(
|
const randomString = faker.git.commitSha({ length: 4 });
|
||||||
params: ServiceParams,
|
|
||||||
): Promise<string> {
|
|
||||||
const emails = params.session?.user?.emails;
|
|
||||||
|
|
||||||
const addressInfoResponse = await Promise.any(
|
// Replace all non-alphanumeric characters with nothing and spaces with dashes
|
||||||
emails
|
const alias = `${faker.color.human()}-${faker.animal.snake()}-${randomString}`
|
||||||
.filter((email: string) => email.endsWith(config.get("wildDuck.preferredDomain")))
|
.replace(/\s+/g, '-')
|
||||||
.map((email: string) =>
|
.replace(/[^a-zA-Z0-9-]/g, '')
|
||||||
wildDuckClient.get<Alias>(`addresses/resolve/${email}`),
|
.toLowerCase();
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return addressInfoResponse.data.user;
|
const emailDomain = config.get('wildDuck.domain');
|
||||||
}
|
|
||||||
|
|
||||||
private async getUserAddresses(userId: string): Promise<Alias[]> {
|
const createResult = await wildDuckClient.post<CreateAddressResponse>(`/users/${userId}/addresses`, {
|
||||||
const { data: userAddressesResponse } =
|
address: `${alias}@${emailDomain}`,
|
||||||
await wildDuckClient.get<GetAddressInfoResponse>(
|
});
|
||||||
`/users/${userId}/addresses`,
|
|
||||||
);
|
|
||||||
|
|
||||||
return userAddressesResponse.results;
|
if (!createResult.data.success) {
|
||||||
}
|
throw new BadRequest('Failed to create alias');
|
||||||
|
}
|
||||||
|
|
||||||
async remove(id: NullableId, params: ServiceParams): Promise<Alias[]> {
|
return this.getUserAddresses(userId);
|
||||||
const { data: addressInfoResponse } = await wildDuckClient.get<Alias>(
|
|
||||||
`addresses/resolve/${id}`,
|
|
||||||
);
|
|
||||||
const allowedDomain: string = config.get("wildDuck.domain");
|
|
||||||
|
|
||||||
// If address does not match the allowed domain, throw an error
|
|
||||||
if (
|
|
||||||
!allowedDomain ||
|
|
||||||
!addressInfoResponse.address.endsWith(allowedDomain)
|
|
||||||
) {
|
|
||||||
throw new BadRequest("Unable to delete address");
|
|
||||||
}
|
}
|
||||||
const userId = await this.getUserIdByEmailAddress(params);
|
|
||||||
|
|
||||||
await wildDuckClient.delete<Alias>(`users/${userId}/addresses/${id}`);
|
private async getUserIdByEmailAddress(params: ServiceParams): Promise<string> {
|
||||||
|
const emails = params.session?.user?.emails;
|
||||||
|
|
||||||
return this.getUserAddresses(userId);
|
const addressInfoResponse = await Promise.any(
|
||||||
}
|
emails
|
||||||
|
.filter((email: string) => email.endsWith(config.get('wildDuck.preferredDomain')))
|
||||||
|
.map((email: string) => wildDuckClient.get<Alias>(`addresses/resolve/${email}`))
|
||||||
|
);
|
||||||
|
|
||||||
|
return addressInfoResponse.data.user;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getUserAddresses(userId: string): Promise<Alias[]> {
|
||||||
|
const { data: userAddressesResponse } = await wildDuckClient.get<GetAddressInfoResponse>(
|
||||||
|
`/users/${userId}/addresses`
|
||||||
|
);
|
||||||
|
|
||||||
|
return userAddressesResponse.results;
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(id: NullableId, params: ServiceParams): Promise<Alias[]> {
|
||||||
|
const { data: addressInfoResponse } = await wildDuckClient.get<Alias>(`addresses/resolve/${id}`);
|
||||||
|
const allowedDomain: string = config.get('wildDuck.domain');
|
||||||
|
|
||||||
|
// If address does not match the allowed domain, throw an error
|
||||||
|
if (!allowedDomain || !addressInfoResponse.address.endsWith(allowedDomain)) {
|
||||||
|
throw new BadRequest('Unable to delete address');
|
||||||
|
}
|
||||||
|
const userId = await this.getUserIdByEmailAddress(params);
|
||||||
|
|
||||||
|
await wildDuckClient.delete<Alias>(`users/${userId}/addresses/${id}`);
|
||||||
|
|
||||||
|
return this.getUserAddresses(userId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getOptions = (app: Application) => {
|
export const getOptions = (app: Application) => {
|
||||||
return { app };
|
return { app };
|
||||||
};
|
};
|
||||||
|
@ -1,39 +1,39 @@
|
|||||||
import type { Application } from "../../declarations";
|
import type { Application } from '../../declarations';
|
||||||
import { validateAuth } from "../../hooks/validate-auth";
|
import { validateAuth } from '../../hooks/validate-auth';
|
||||||
import { AliasesService, getOptions } from "./aliases.class";
|
import { AliasesService, getOptions } from './aliases.class';
|
||||||
|
|
||||||
export const aliasesPath = "aliases";
|
export const aliasesPath = 'aliases';
|
||||||
export const aliasesMethods = ["find", "create", "remove"] as const;
|
export const aliasesMethods = ['find', 'create', 'remove'] as const;
|
||||||
|
|
||||||
export * from "./aliases.class";
|
export * from './aliases.class';
|
||||||
|
|
||||||
export const aliases = (app: Application) => {
|
export const aliases = (app: Application) => {
|
||||||
app.use(aliasesPath, new AliasesService(getOptions(app)), {
|
app.use(aliasesPath, new AliasesService(getOptions(app)), {
|
||||||
methods: aliasesMethods,
|
methods: aliasesMethods,
|
||||||
events: [],
|
events: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
app.service(aliasesPath).hooks({
|
app.service(aliasesPath).hooks({
|
||||||
around: {
|
around: {
|
||||||
all: [],
|
all: [],
|
||||||
},
|
},
|
||||||
before: {
|
before: {
|
||||||
all: [validateAuth],
|
all: [validateAuth],
|
||||||
find: [],
|
find: [],
|
||||||
create: [],
|
create: [],
|
||||||
},
|
},
|
||||||
after: {
|
after: {
|
||||||
all: [],
|
all: [],
|
||||||
},
|
},
|
||||||
error: {
|
error: {
|
||||||
all: [],
|
all: [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add this service to the service type index
|
// Add this service to the service type index
|
||||||
declare module "../../declarations" {
|
declare module '../../declarations' {
|
||||||
interface ServiceTypes {
|
interface ServiceTypes {
|
||||||
[aliasesPath]: AliasesService;
|
[aliasesPath]: AliasesService;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import type { Params, ServiceInterface } from "@feathersjs/feathers";
|
import type { Params, ServiceInterface } from '@feathersjs/feathers';
|
||||||
|
|
||||||
import type { Application } from "../../declarations";
|
import type { Application } from '../../declarations';
|
||||||
|
|
||||||
import { Issuer, generators } from "openid-client";
|
import { Issuer, generators } from 'openid-client';
|
||||||
import config from "config";
|
import config from 'config';
|
||||||
|
|
||||||
type AuthOidcResponse = string;
|
type AuthOidcResponse = string;
|
||||||
type AuthOidcQuery = any;
|
type AuthOidcQuery = any;
|
||||||
@ -11,43 +11,42 @@ type AuthOidcQuery = any;
|
|||||||
export type { AuthOidcResponse as AuthOidc, AuthOidcQuery };
|
export type { AuthOidcResponse as AuthOidc, AuthOidcQuery };
|
||||||
|
|
||||||
export interface AuthOidcServiceOptions {
|
export interface AuthOidcServiceOptions {
|
||||||
app: Application;
|
app: Application;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AuthOidcParams extends Params<AuthOidcQuery> {
|
export interface AuthOidcParams extends Params<AuthOidcQuery> {
|
||||||
session?: any;
|
session?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AuthOidcService<
|
export class AuthOidcService<ServiceParams extends AuthOidcParams = AuthOidcParams>
|
||||||
ServiceParams extends AuthOidcParams = AuthOidcParams,
|
implements ServiceInterface<AuthOidcResponse, ServiceParams>
|
||||||
> implements ServiceInterface<AuthOidcResponse, ServiceParams>
|
|
||||||
{
|
{
|
||||||
constructor(public options: AuthOidcServiceOptions) {}
|
constructor(public options: AuthOidcServiceOptions) {}
|
||||||
|
|
||||||
async find(params: ServiceParams): Promise<AuthOidcResponse> {
|
async find(params: ServiceParams): Promise<AuthOidcResponse> {
|
||||||
const issuer = await Issuer.discover(config.get("oidc.gatewayUri"));
|
const issuer = await Issuer.discover(config.get('oidc.gatewayUri'));
|
||||||
const client = new issuer.Client({
|
const client = new issuer.Client({
|
||||||
client_id: config.get("oidc.clientId"),
|
client_id: config.get('oidc.clientId'),
|
||||||
client_secret: config.get("oidc.clientSecret"),
|
client_secret: config.get('oidc.clientSecret'),
|
||||||
redirect_uris: [config.get("oidc.redirectUris")],
|
redirect_uris: [config.get('oidc.redirectUris')],
|
||||||
response_types: ["code"],
|
response_types: ['code'],
|
||||||
});
|
});
|
||||||
const codeVerifier = generators.codeVerifier();
|
const codeVerifier = generators.codeVerifier();
|
||||||
const codeChallenge = generators.codeChallenge(codeVerifier);
|
const codeChallenge = generators.codeChallenge(codeVerifier);
|
||||||
|
|
||||||
const url = client.authorizationUrl({
|
const url = client.authorizationUrl({
|
||||||
redirect_uri: config.get("clientUrl") + "/auth-oidc/callback",
|
redirect_uri: config.get('clientUrl') + '/auth-oidc/callback',
|
||||||
scope: "openid profile offline_access",
|
scope: 'openid profile offline_access',
|
||||||
response_type: "code",
|
response_type: 'code',
|
||||||
code_challenge: codeChallenge,
|
code_challenge: codeChallenge,
|
||||||
code_challenge_method: "S256",
|
code_challenge_method: 'S256',
|
||||||
});
|
});
|
||||||
|
|
||||||
params.session.codeVerifier = codeVerifier;
|
params.session.codeVerifier = codeVerifier;
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getOptions = (app: Application) => {
|
export const getOptions = (app: Application) => {
|
||||||
return { app };
|
return { app };
|
||||||
};
|
};
|
||||||
|
@ -1,45 +1,45 @@
|
|||||||
import type { Application } from "../../declarations";
|
import type { Application } from '../../declarations';
|
||||||
import { AuthOidcService, getOptions } from "./auth-oidc.class";
|
import { AuthOidcService, getOptions } from './auth-oidc.class';
|
||||||
|
|
||||||
export const authOidcPath = "auth-oidc";
|
export const authOidcPath = 'auth-oidc';
|
||||||
export const authOidcMethods = ["find"] as const;
|
export const authOidcMethods = ['find'] as const;
|
||||||
|
|
||||||
export * from "./auth-oidc.class";
|
export * from './auth-oidc.class';
|
||||||
|
|
||||||
export const authOidc = (app: Application) => {
|
export const authOidc = (app: Application) => {
|
||||||
// TODO: fix this to use the correct type
|
// TODO: fix this to use the correct type
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
app.use(
|
app.use(
|
||||||
authOidcPath,
|
authOidcPath,
|
||||||
new AuthOidcService(getOptions(app)),
|
new AuthOidcService(getOptions(app)),
|
||||||
{
|
{
|
||||||
methods: authOidcMethods,
|
methods: authOidcMethods,
|
||||||
events: [],
|
events: [],
|
||||||
},
|
},
|
||||||
(req: any, res: any) => {
|
(req: any, res: any) => {
|
||||||
return res.redirect(res.data);
|
return res.redirect(res.data);
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
app.service(authOidcPath).hooks({
|
app.service(authOidcPath).hooks({
|
||||||
around: {
|
around: {
|
||||||
all: [],
|
all: [],
|
||||||
},
|
},
|
||||||
before: {
|
before: {
|
||||||
all: [],
|
all: [],
|
||||||
find: [],
|
find: [],
|
||||||
},
|
},
|
||||||
after: {
|
after: {
|
||||||
all: [],
|
all: [],
|
||||||
},
|
},
|
||||||
error: {
|
error: {
|
||||||
all: [],
|
all: [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
declare module "../../declarations" {
|
declare module '../../declarations' {
|
||||||
interface ServiceTypes {
|
interface ServiceTypes {
|
||||||
[authOidcPath]: AuthOidcService;
|
[authOidcPath]: AuthOidcService;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,68 +1,56 @@
|
|||||||
import type { Params, ServiceInterface } from "@feathersjs/feathers";
|
import type { Params, ServiceInterface } from '@feathersjs/feathers';
|
||||||
import type { Application } from "../../../declarations";
|
import type { Application } from '../../../declarations';
|
||||||
import { Issuer } from "openid-client";
|
import { Issuer } from 'openid-client';
|
||||||
|
|
||||||
import config from "config";
|
import config from 'config';
|
||||||
|
|
||||||
type AuthOidcCallback = string;
|
type AuthOidcCallback = string;
|
||||||
type AuthOidcCallbackData = any;
|
type AuthOidcCallbackData = any;
|
||||||
type AuthOidcCallbackPatch = any;
|
type AuthOidcCallbackPatch = any;
|
||||||
type AuthOidcCallbackQuery = any;
|
type AuthOidcCallbackQuery = any;
|
||||||
|
|
||||||
export type {
|
export type { AuthOidcCallback, AuthOidcCallbackData, AuthOidcCallbackPatch, AuthOidcCallbackQuery };
|
||||||
AuthOidcCallback,
|
|
||||||
AuthOidcCallbackData,
|
|
||||||
AuthOidcCallbackPatch,
|
|
||||||
AuthOidcCallbackQuery,
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface AuthOidcCallbackServiceOptions {
|
export interface AuthOidcCallbackServiceOptions {
|
||||||
app: Application;
|
app: Application;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AuthOidcCallbackParams extends Params<AuthOidcCallbackQuery> {
|
export interface AuthOidcCallbackParams extends Params<AuthOidcCallbackQuery> {
|
||||||
session?: any;
|
session?: any;
|
||||||
query: {
|
query: {
|
||||||
iss: string;
|
iss: string;
|
||||||
code: string;
|
code: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AuthOidcCallbackService<
|
export class AuthOidcCallbackService<ServiceParams extends AuthOidcCallbackParams = AuthOidcCallbackParams>
|
||||||
ServiceParams extends AuthOidcCallbackParams = AuthOidcCallbackParams,
|
implements ServiceInterface<AuthOidcCallback, AuthOidcCallbackData, ServiceParams, AuthOidcCallbackPatch>
|
||||||
> implements
|
|
||||||
ServiceInterface<
|
|
||||||
AuthOidcCallback,
|
|
||||||
AuthOidcCallbackData,
|
|
||||||
ServiceParams,
|
|
||||||
AuthOidcCallbackPatch
|
|
||||||
>
|
|
||||||
{
|
{
|
||||||
constructor(public options: AuthOidcCallbackServiceOptions) {}
|
constructor(public options: AuthOidcCallbackServiceOptions) {}
|
||||||
|
|
||||||
async find(params: ServiceParams): Promise<AuthOidcCallback> {
|
async find(params: ServiceParams): Promise<AuthOidcCallback> {
|
||||||
const issuer = await Issuer.discover(config.get("oidc.gatewayUri"));
|
const issuer = await Issuer.discover(config.get('oidc.gatewayUri'));
|
||||||
const client = new issuer.Client({
|
const client = new issuer.Client({
|
||||||
client_id: config.get("oidc.clientId"),
|
client_id: config.get('oidc.clientId'),
|
||||||
client_secret: config.get("oidc.clientSecret"),
|
client_secret: config.get('oidc.clientSecret'),
|
||||||
redirect_uris: [config.get("oidc.redirectUris")],
|
redirect_uris: [config.get('oidc.redirectUris')],
|
||||||
response_types: ["code"],
|
response_types: ['code'],
|
||||||
});
|
});
|
||||||
|
|
||||||
const codeVerifier = params.session.codeVerifier;
|
const codeVerifier = params.session.codeVerifier;
|
||||||
const tokenSet = await client.callback(
|
const tokenSet = await client.callback(
|
||||||
config.get("clientUrl") + "/auth-oidc/callback",
|
config.get('clientUrl') + '/auth-oidc/callback',
|
||||||
{ code: params.query.code, iss: params.query.iss },
|
{ code: params.query.code, iss: params.query.iss },
|
||||||
{ code_verifier: codeVerifier },
|
{ code_verifier: codeVerifier }
|
||||||
);
|
);
|
||||||
const userinfo = await client.userinfo(tokenSet.access_token as string);
|
const userinfo = await client.userinfo(tokenSet.access_token as string);
|
||||||
|
|
||||||
params.session.user = userinfo;
|
params.session.user = userinfo;
|
||||||
|
|
||||||
return "/";
|
return '/';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getOptions = (app: Application) => {
|
export const getOptions = (app: Application) => {
|
||||||
return { app };
|
return { app };
|
||||||
};
|
};
|
||||||
|
@ -1,49 +1,46 @@
|
|||||||
import { http } from "@feathersjs/transport-commons";
|
import { http } from '@feathersjs/transport-commons';
|
||||||
import type { Application } from "../../../declarations";
|
import type { Application } from '../../../declarations';
|
||||||
import {
|
import { AuthOidcCallbackService, getOptions } from './auth-oidc-callback.class';
|
||||||
AuthOidcCallbackService,
|
|
||||||
getOptions,
|
|
||||||
} from "./auth-oidc-callback.class";
|
|
||||||
|
|
||||||
export const authOidcCallbackPath = "auth-oidc/callback";
|
export const authOidcCallbackPath = 'auth-oidc/callback';
|
||||||
export const authOidcCallbackMethods = ["find"] as const;
|
export const authOidcCallbackMethods = ['find'] as const;
|
||||||
|
|
||||||
export * from "./auth-oidc-callback.class";
|
export * from './auth-oidc-callback.class';
|
||||||
|
|
||||||
export const authOidcCallback = (app: Application) => {
|
export const authOidcCallback = (app: Application) => {
|
||||||
// TODO: fix this to use the correct type
|
// TODO: fix this to use the correct type
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
app.use(
|
app.use(
|
||||||
authOidcCallbackPath,
|
authOidcCallbackPath,
|
||||||
new AuthOidcCallbackService(getOptions(app)),
|
new AuthOidcCallbackService(getOptions(app)),
|
||||||
{
|
{
|
||||||
methods: authOidcCallbackMethods,
|
methods: authOidcCallbackMethods,
|
||||||
events: [],
|
events: [],
|
||||||
},
|
},
|
||||||
(req: any, res: any) => {
|
(req: any, res: any) => {
|
||||||
return res.redirect(res.data);
|
return res.redirect(res.data);
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
app.service(authOidcCallbackPath).hooks({
|
app.service(authOidcCallbackPath).hooks({
|
||||||
around: {
|
around: {
|
||||||
all: [],
|
all: [],
|
||||||
},
|
},
|
||||||
before: {
|
before: {
|
||||||
all: [],
|
all: [],
|
||||||
find: [],
|
find: [],
|
||||||
},
|
},
|
||||||
after: {
|
after: {
|
||||||
all: [],
|
all: [],
|
||||||
},
|
},
|
||||||
error: {
|
error: {
|
||||||
all: [],
|
all: [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
declare module "../../../declarations" {
|
declare module '../../../declarations' {
|
||||||
interface ServiceTypes {
|
interface ServiceTypes {
|
||||||
[authOidcCallbackPath]: AuthOidcCallbackService;
|
[authOidcCallbackPath]: AuthOidcCallbackService;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { authOidcCallback } from "./auth-oidc/callback/auth-oidc-callback";
|
import { authOidcCallback } from './auth-oidc/callback/auth-oidc-callback';
|
||||||
import { authOidc } from "./auth-oidc/auth-oidc";
|
import { authOidc } from './auth-oidc/auth-oidc';
|
||||||
import { aliases } from "./aliases/aliases";
|
import { aliases } from './aliases/aliases';
|
||||||
import type { Application } from "../declarations";
|
import type { Application } from '../declarations';
|
||||||
|
|
||||||
export const services = (app: Application) => {
|
export const services = (app: Application) => {
|
||||||
app.configure(authOidcCallback);
|
app.configure(authOidcCallback);
|
||||||
app.configure(authOidc);
|
app.configure(authOidc);
|
||||||
app.configure(aliases);
|
app.configure(aliases);
|
||||||
};
|
};
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
// For more information about this file see https://dove.feathersjs.com/guides/cli/validators.html
|
// For more information about this file see https://dove.feathersjs.com/guides/cli/validators.html
|
||||||
import { Ajv, addFormats } from "@feathersjs/schema";
|
import { Ajv, addFormats } from '@feathersjs/schema';
|
||||||
import type { FormatsPluginOptions } from "@feathersjs/schema";
|
import type { FormatsPluginOptions } from '@feathersjs/schema';
|
||||||
|
|
||||||
const formats: FormatsPluginOptions = [
|
const formats: FormatsPluginOptions = [
|
||||||
"date-time",
|
'date-time',
|
||||||
"time",
|
'time',
|
||||||
"date",
|
'date',
|
||||||
"email",
|
'email',
|
||||||
"hostname",
|
'hostname',
|
||||||
"ipv4",
|
'ipv4',
|
||||||
"ipv6",
|
'ipv6',
|
||||||
"uri",
|
'uri',
|
||||||
"uri-reference",
|
'uri-reference',
|
||||||
"uuid",
|
'uuid',
|
||||||
"uri-template",
|
'uri-template',
|
||||||
"json-pointer",
|
'json-pointer',
|
||||||
"relative-json-pointer",
|
'relative-json-pointer',
|
||||||
"regex",
|
'regex',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const dataValidator: Ajv = addFormats(new Ajv({}), formats);
|
export const dataValidator: Ajv = addFormats(new Ajv({}), formats);
|
||||||
|
|
||||||
export const queryValidator: Ajv = addFormats(
|
export const queryValidator: Ajv = addFormats(
|
||||||
new Ajv({
|
new Ajv({
|
||||||
coerceTypes: true,
|
coerceTypes: true,
|
||||||
}),
|
}),
|
||||||
formats,
|
formats
|
||||||
);
|
);
|
||||||
|
@ -1,40 +1,40 @@
|
|||||||
// For more information about this file see https://dove.feathersjs.com/guides/cli/app.test.html
|
// For more information about this file see https://dove.feathersjs.com/guides/cli/app.test.html
|
||||||
import assert from "assert";
|
import assert from 'assert';
|
||||||
import axios from "axios";
|
import axios from 'axios';
|
||||||
import type { Server } from "http";
|
import type { Server } from 'http';
|
||||||
import { app } from "../src/app";
|
import { app } from '../src/app';
|
||||||
|
|
||||||
const port = app.get("port");
|
const port = app.get('port');
|
||||||
const appUrl = `http://${app.get("host")}:${port}`;
|
const appUrl = `http://${app.get('host')}:${port}`;
|
||||||
|
|
||||||
describe("Feathers application tests", () => {
|
describe('Feathers application tests', () => {
|
||||||
let server: Server;
|
let server: Server;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
server = await app.listen(port);
|
server = await app.listen(port);
|
||||||
});
|
});
|
||||||
|
|
||||||
after(async () => {
|
after(async () => {
|
||||||
await app.teardown();
|
await app.teardown();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("starts and shows the index page", async () => {
|
it('starts and shows the index page', async () => {
|
||||||
const { data } = await axios.get<string>(appUrl);
|
const { data } = await axios.get<string>(appUrl);
|
||||||
|
|
||||||
assert.ok(data.indexOf('<html lang="en">') !== -1);
|
assert.ok(data.indexOf('<html lang="en">') !== -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows a 404 JSON error", async () => {
|
it('shows a 404 JSON error', async () => {
|
||||||
try {
|
try {
|
||||||
await axios.get(`${appUrl}/path/to/nowhere`, {
|
await axios.get(`${appUrl}/path/to/nowhere`, {
|
||||||
responseType: "json",
|
responseType: 'json',
|
||||||
});
|
});
|
||||||
assert.fail("should never get here");
|
assert.fail('should never get here');
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const { response } = error;
|
const { response } = error;
|
||||||
assert.strictEqual(response?.status, 404);
|
assert.strictEqual(response?.status, 404);
|
||||||
assert.strictEqual(response?.data?.code, 404);
|
assert.strictEqual(response?.data?.code, 404);
|
||||||
assert.strictEqual(response?.data?.name, "NotFound");
|
assert.strictEqual(response?.data?.name, 'NotFound');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
// For more information about this file see https://dove.feathersjs.com/guides/cli/service.test.html
|
// For more information about this file see https://dove.feathersjs.com/guides/cli/service.test.html
|
||||||
import assert from "assert";
|
import assert from 'assert';
|
||||||
import { app } from "../../../src/app";
|
import { app } from '../../../src/app';
|
||||||
|
|
||||||
describe("aliases service", () => {
|
describe('aliases service', () => {
|
||||||
it("registered the service", () => {
|
it('registered the service', () => {
|
||||||
const service = app.service("aliases");
|
const service = app.service('aliases');
|
||||||
|
|
||||||
assert.ok(service, "Registered the service");
|
assert.ok(service, 'Registered the service');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
// For more information about this file see https://dove.feathersjs.com/guides/cli/service.test.html
|
// For more information about this file see https://dove.feathersjs.com/guides/cli/service.test.html
|
||||||
import assert from "assert";
|
import assert from 'assert';
|
||||||
import { app } from "../../../src/app";
|
import { app } from '../../../src/app';
|
||||||
|
|
||||||
describe("auth-oidc service", () => {
|
describe('auth-oidc service', () => {
|
||||||
it("registered the service", () => {
|
it('registered the service', () => {
|
||||||
const service = app.service("auth-oidc");
|
const service = app.service('auth-oidc');
|
||||||
|
|
||||||
assert.ok(service, "Registered the service");
|
assert.ok(service, 'Registered the service');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
// For more information about this file see https://dove.feathersjs.com/guides/cli/service.test.html
|
// For more information about this file see https://dove.feathersjs.com/guides/cli/service.test.html
|
||||||
import assert from "assert";
|
import assert from 'assert';
|
||||||
import { app } from "../../../../src/app";
|
import { app } from '../../../../src/app';
|
||||||
|
|
||||||
describe("auth-oidc/callback service", () => {
|
describe('auth-oidc/callback service', () => {
|
||||||
it("registered the service", () => {
|
it('registered the service', () => {
|
||||||
const service = app.service("auth-oidc/callback");
|
const service = app.service('auth-oidc/callback');
|
||||||
|
|
||||||
assert.ok(service, "Registered the service");
|
assert.ok(service, 'Registered the service');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
// For more information about this file see https://dove.feathersjs.com/guides/cli/validators.html
|
|
||||||
import { Ajv, addFormats } from "@feathersjs/schema";
|
|
||||||
import type { FormatsPluginOptions } from "@feathersjs/schema";
|
|
||||||
|
|
||||||
const formats: FormatsPluginOptions = [
|
|
||||||
"date-time",
|
|
||||||
"time",
|
|
||||||
"date",
|
|
||||||
"email",
|
|
||||||
"hostname",
|
|
||||||
"ipv4",
|
|
||||||
"ipv6",
|
|
||||||
"uri",
|
|
||||||
"uri-reference",
|
|
||||||
"uuid",
|
|
||||||
"uri-template",
|
|
||||||
"json-pointer",
|
|
||||||
"relative-json-pointer",
|
|
||||||
"regex",
|
|
||||||
];
|
|
||||||
|
|
||||||
export const dataValidator: Ajv = addFormats(new Ajv({}), formats);
|
|
||||||
|
|
||||||
export const queryValidator: Ajv = addFormats(
|
|
||||||
new Ajv({
|
|
||||||
coerceTypes: true,
|
|
||||||
}),
|
|
||||||
formats,
|
|
||||||
);
|
|
Loading…
Reference in New Issue
Block a user