diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..7c5c224 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +dist +*.js \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..fcfc1a5 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,59 @@ +{ + "env": { + "node": true, + "commonjs": true, + "es6": true + }, + "parser": "@typescript-eslint/parser", + "globals": { + "BigInt": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "plugins": [ + "@typescript-eslint" + ], + "rules": { + "require-atomic-updates": "warn", + "no-case-declarations": "off", + "no-empty": "off", + "no-console": "off", + "linebreak-style": "off", + "no-global-assign": "off", + "prefer-const": "error", + "no-var": "error", + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], + "no-extra-semi": "off", + "@typescript-eslint/no-extra-semi": "error", + "@typescript-eslint/no-empty-interface": "warn", + "@typescript-eslint/no-inferrable-types": "error", + "@typescript-eslint/typedef": "error", + "@typescript-eslint/explicit-function-return-type": "error", + "keyword-spacing": "off", + "@typescript-eslint/keyword-spacing": "error", + "curly": "error", + "brace-style": "error", + "one-var": [ + "error", + "never" + ], + "indent": [ + "error", + "tab", + { + "SwitchCase": 1 + } + ], + "quotes": [ + "error", + "single" + ], + "semi": [ + "error", + "always" + ] + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 78a27fb..5fd99bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,136 @@ -.DS_Store -node_modules +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# custom certs -config.json -src/logs +logs +dist +newman \ No newline at end of file diff --git a/.postman/api b/.postman/api new file mode 100644 index 0000000..cd3d9e2 --- /dev/null +++ b/.postman/api @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY +apis[] = {"apiId":"093b0c82-779f-419f-9aca-029910a07e65"} +configVersion = 1.0.0 +type = api diff --git a/.postman/api_093b0c82-779f-419f-9aca-029910a07e65 b/.postman/api_093b0c82-779f-419f-9aca-029910a07e65 new file mode 100644 index 0000000..5ae6271 --- /dev/null +++ b/.postman/api_093b0c82-779f-419f-9aca-029910a07e65 @@ -0,0 +1,20 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY +configVersion = 1.0.0 +type = apiEntityData + +[config] +id = 093b0c82-779f-419f-9aca-029910a07e65 + +[config.relations] + +[config.relations.collections] +rootDirectory = postman/collections +files[] = {"id":"19511066-cb605935-6073-42c5-afa9-96d9a19c70a3","path":"Communities.json","metaData":{}} +files[] = {"id":"19511066-2bb4ba1f-8e09-44b9-9ad1-5f59455c0ba7","path":"People.json","metaData":{}} + +[config.relations.collections.metaData] + +[config.relations.apiDefinition] +rootDirectory = postman/schemas + +[config.relations.apiDefinition.metaData] diff --git a/config.example.json b/config.example.json deleted file mode 100644 index 0dfda3a..0000000 --- a/config.example.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "http": { - "port": 8081 - }, - "account_server": "account.miiverse.cc:8080", - "secret": "806590af0a2bf0cf9ce54b0b5c1493a1", - "X-Nintendo-Client-ID": "a2efa818a34fa16b8afbc8a74eba3eda", - "X-Nintendo-Client-Secret": "c91cdb5658bd4954ade78533a339cf9a", - "mongoose": { - "uri": "mongodb://localhost:27017", - "database": "Miiverse", - "options": { - "useNewUrlParser": true, - "useUnifiedTopology": true - } - }, - "authorized_PNIDs" : [ - 1420636409, 1657414049, 1587572630 - ] -} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index c5f5384..a24acda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,1496 +1,6508 @@ { - "name": "pretendoverse", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@oozcitak/dom": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-0.0.11.tgz", - "integrity": "sha512-BUNzbWpSn0Y7Yo8qgjVCM0axw2A6ncZaY7iC8msZIpuL6vYDP19zRqYI5bYWgBkgDXiap4cFEFsFrauyYAgKnw==", - "requires": { - "@oozcitak/infra": "1.0.4", - "@oozcitak/url": "0.0.8", - "@oozcitak/util": "1.0.2" - }, - "dependencies": { - "@oozcitak/util": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-1.0.2.tgz", - "integrity": "sha512-4n8B1cWlJleSOSba5gxsMcN4tO8KkkcvXhNWW+ADqvq9Xj+Lrl9uCa90GRpjekqQJyt84aUX015DG81LFpZYXA==" - } - } - }, - "@oozcitak/infra": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-1.0.4.tgz", - "integrity": "sha512-PIYPFk/MUzdhdeEBWL8TOEmEHyN60pWDCzXdN6XyNQHwt1i0YNUCOZ434Qa8WNuwJlOCNTrZFK8nlirIOF06Eg==", - "requires": { - "@oozcitak/util": "1.0.2" - }, - "dependencies": { - "@oozcitak/util": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-1.0.2.tgz", - "integrity": "sha512-4n8B1cWlJleSOSba5gxsMcN4tO8KkkcvXhNWW+ADqvq9Xj+Lrl9uCa90GRpjekqQJyt84aUX015DG81LFpZYXA==" - } - } - }, - "@oozcitak/url": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/@oozcitak/url/-/url-0.0.8.tgz", - "integrity": "sha512-PR1ZCwaYvm781f0V14y2Uu8CM94k/znGfNpzJive5XjuDuCtMDFB3MYhSdVNZDG95faupVuFTph2lzn38S0zKg==", - "requires": { - "@oozcitak/infra": "1.0.3", - "@oozcitak/util": "1.0.2", - "@oozcitak/uts46": "0.0.8" - }, - "dependencies": { - "@oozcitak/infra": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-1.0.3.tgz", - "integrity": "sha512-9O2wxXGnRzy76O1XUxESxDGsXT5kzETJPvYbreO4mv6bqe1+YSuux2cZTagjJ/T4UfEwFJz5ixanOqB0QgYAag==", - "requires": { - "@oozcitak/util": "1.0.1" - }, - "dependencies": { - "@oozcitak/util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-1.0.1.tgz", - "integrity": "sha512-dFwFqcKrQnJ2SapOmRD1nQWEZUtbtIy9Y6TyJquzsalWNJsKIPxmTI0KG6Ypyl8j7v89L2wixH9fQDNrF78hKg==" - } - } - }, - "@oozcitak/util": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-1.0.2.tgz", - "integrity": "sha512-4n8B1cWlJleSOSba5gxsMcN4tO8KkkcvXhNWW+ADqvq9Xj+Lrl9uCa90GRpjekqQJyt84aUX015DG81LFpZYXA==" - } - } - }, - "@oozcitak/util": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-1.0.3.tgz", - "integrity": "sha512-md38Xc0kBJ8I4aBI13xtX7r4RtSi9HByNVaqcVQeal3PSSbPKmtX1l6+8/YbfaIcP+fyLuwnOxHpYoh/R2DONw==" - }, - "@oozcitak/uts46": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/@oozcitak/uts46/-/uts46-0.0.8.tgz", - "integrity": "sha512-/m/ytADxqWfGiNvenR5wkX7NGBRKQlypufv0w2NRAoWIGDuRLeweClJPRxV41Mln3HNtlF08OKoFFRUG8ztvGQ==", - "requires": { - "@oozcitak/util": "1.0.2", - "punycode": "2.1.1" - }, - "dependencies": { - "@oozcitak/util": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-1.0.2.tgz", - "integrity": "sha512-4n8B1cWlJleSOSba5gxsMcN4tO8KkkcvXhNWW+ADqvq9Xj+Lrl9uCa90GRpjekqQJyt84aUX015DG81LFpZYXA==" - } - } - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "ajv": { - "version": "6.12.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", - "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=", - "dev": true - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", - "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==", - "dev": true - }, - "basic-auth": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "bl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.0.tgz", - "integrity": "sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==", - "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, - "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" - }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - } - }, - "bson": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.4.tgz", - "integrity": "sha512-S/yKGU1syOMzO86+dGpg2qGoDL0zvzcb262G+gqEy6TgP6rt6z6qxSFX/8X6vLC91P7G7C3nLs0+bvDzmvBA3Q==" - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "busboy": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", - "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", - "dev": true, - "requires": { - "dicer": "0.2.5", - "readable-stream": "1.1.x" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "dank-each": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dank-each/-/dank-each-1.0.0.tgz", - "integrity": "sha1-qGE0Okso02IgPUBcd4ZNyaZANzA=", - "dev": true - }, - "dank-map": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/dank-map/-/dank-map-0.1.0.tgz", - "integrity": "sha1-6Z5384LGjy5asrPzqCuAMZV1Kag=", - "dev": true - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "denque": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", - "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "dicer": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", - "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", - "dev": true, - "requires": { - "readable-stream": "1.1.x", - "streamsearch": "0.1.2" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - } - }, - "express-session": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.0.tgz", - "integrity": "sha512-t4oX2z7uoSqATbMfsxWMbNjAL0T5zpvcJCk3Z9wnPPN7ibddhnmDZXHfEcoBMG2ojKXZoCyPMc5FbtK+G7SoDg==", - "requires": { - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-headers": "~1.0.2", - "parseurl": "~1.3.3", - "safe-buffer": "5.2.0", - "uid-safe": "~2.1.5" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" - } - } - }, - "express-subdomain": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/express-subdomain/-/express-subdomain-1.0.5.tgz", - "integrity": "sha1-mQ75eUC39MKCPZWTZIt5voWKY4s=" - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "fs-extra": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz", - "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==", - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^1.0.0" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", - "dev": true - }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isemail": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", - "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", - "dev": true, - "requires": { - "punycode": "2.x.x" - } - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "joi": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-13.7.0.tgz", - "integrity": "sha512-xuY5VkHfeOYK3Hdi91ulocfuFopwgbSORmIwzcwHKESQhC7w1kD5jaVSPnqDxS2I8t3RZ9omCKAxNwXN5zG1/Q==", - "dev": true, - "requires": { - "hoek": "5.x.x", - "isemail": "3.x.x", - "topo": "3.x.x" - }, - "dependencies": { - "hoek": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.4.tgz", - "integrity": "sha512-Alr4ZQgoMlnere5FZJsIyfIjORBqZll5POhDsF4q64dPuJR6rNxXdDxtHSQq8OXRurhmx+PWYEE8bXRROY8h0w==", - "dev": true - } - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "jsonfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", - "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^1.0.0" - } - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "kareem": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz", - "integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw==" - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - }, - "lodash.foreach": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", - "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=" - }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "memory-pager": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "optional": true - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", - "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" - }, - "mime-types": { - "version": "2.1.26", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", - "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", - "requires": { - "mime-db": "1.43.0" - } - }, - "minimist": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", - "dev": true - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" - }, - "moment-timezone": { - "version": "0.5.35", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.35.tgz", - "integrity": "sha512-cY/pBOEXepQvlgli06ttCTKcIf8cD1nmNwOKQQAdHBqYApQSpAqotBMX0RJZNgMp6i0PlZuf1mFtnlyEkwyvFw==", - "requires": { - "moment": ">= 2.9.0" - } - }, - "mongodb": { - "version": "3.5.7", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.7.tgz", - "integrity": "sha512-lMtleRT+vIgY/JhhTn1nyGwnSMmJkJELp+4ZbrjctrnBxuLbj6rmLuJFz8W2xUzUqWmqoyVxJLYuC58ZKpcTYQ==", - "requires": { - "bl": "^2.2.0", - "bson": "^1.1.4", - "denque": "^1.4.1", - "require_optional": "^1.0.1", - "safe-buffer": "^5.1.2", - "saslprep": "^1.0.0" - } - }, - "mongoose": { - "version": "5.9.16", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.9.16.tgz", - "integrity": "sha512-b4HNndgh+dacoLE/2SBF3iBBofeaKL+aGVZH7jnPRc2RXRCplX4sfH5sgoz03ryCSXJ+RQNIfqKAADt/ZBzPDA==", - "requires": { - "bson": "^1.1.4", - "kareem": "2.3.1", - "mongodb": "3.5.7", - "mongoose-legacy-pluralize": "1.0.2", - "mpath": "0.7.0", - "mquery": "3.2.2", - "ms": "2.1.2", - "regexp-clone": "1.0.0", - "safe-buffer": "5.1.2", - "sift": "7.0.1", - "sliced": "1.0.1" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "mongoose-legacy-pluralize": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", - "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" - }, - "mongoose-unique-validator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/mongoose-unique-validator/-/mongoose-unique-validator-2.0.3.tgz", - "integrity": "sha512-3/8pmvAC1acBZS6eWKAWQUiZBlARE1wyWtjga4iQ2wDJeOfRlIKmAvTNHSZXKaAf7RCRUd7wh7as6yWAOrjpQg==", - "requires": { - "lodash.foreach": "^4.1.0", - "lodash.get": "^4.0.2" - } - }, - "morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", - "requires": { - "basic-auth": "~2.0.1", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-finished": "~2.3.0", - "on-headers": "~1.0.2" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - } - } - }, - "mpath": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.7.0.tgz", - "integrity": "sha512-Aiq04hILxhz1L+f7sjGyn7IxYzWm1zLNNXcfhDtx04kZ2Gk7uvFdgZ8ts1cWa/6d0TQmag2yR8zSGZUmp0tFNg==" - }, - "mquery": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.2.tgz", - "integrity": "sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q==", - "requires": { - "bluebird": "3.5.1", - "debug": "3.1.0", - "regexp-clone": "^1.0.0", - "safe-buffer": "5.1.2", - "sliced": "1.0.1" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "multer": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.2.tgz", - "integrity": "sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==", - "dev": true, - "requires": { - "append-field": "^1.0.0", - "busboy": "^0.2.11", - "concat-stream": "^1.5.2", - "mkdirp": "^0.5.1", - "object-assign": "^4.1.1", - "on-finished": "^2.3.0", - "type-is": "^1.6.4", - "xtend": "^4.0.0" - } - }, - "nan": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", - "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", - "dev": true - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" - }, - "node-expat": { - "version": "2.3.18", - "resolved": "https://registry.npmjs.org/node-expat/-/node-expat-2.3.18.tgz", - "integrity": "sha512-9dIrDxXePa9HSn+hhlAg1wXkvqOjxefEbMclGxk2cEnq/Y3U7Qo5HNNqeo3fQ4bVmLhcdt3YN1TZy7WMZy4MHw==", - "dev": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.13.2" - } - }, - "node-rsa": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-1.0.8.tgz", - "integrity": "sha512-q8knkMHEqViIX/fshOltCHTtlt4Nw5wpBpu0//LB1tkxqYZB/001dYMwbPvTPiENwKvPqVDkhxK6J4fV09oa7w==", - "requires": { - "asn1": "^0.2.4" - } - }, - "node-snowflake": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/node-snowflake/-/node-snowflake-0.0.1.tgz", - "integrity": "sha1-C+XqvVsRMfY55j6JxfgtqoFLOrk=" - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-to-xml": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/object-to-xml/-/object-to-xml-2.0.0.tgz", - "integrity": "sha512-bArXy7WCF1V9R88/zF9adSZSeFQnFmmKhMqNuNLAxqrbkvzcWP8HgnaRCcVJsfvIgvpdHiYd0qzJi7LM7QFfcQ==", - "dev": true, - "requires": { - "dank-each": "^1.0.0", - "dank-map": "~0.1.0", - "sanitizer": "0.1.3" - } - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" - }, - "pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "pngjs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", - "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, - "proxy-addr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", - "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.1" - } - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" - }, - "random-bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", - "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "regexp-clone": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz", - "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw==" - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true - } - } - }, - "require_optional": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", - "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", - "requires": { - "resolve-from": "^2.0.0", - "semver": "^5.1.0" - } - }, - "resolve-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sanitize": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sanitize/-/sanitize-2.1.0.tgz", - "integrity": "sha512-HLDVriFJnrm6ElDe2E8alAKDMZGMtM8CdKhvunp9592j8hNwZmmsmhk/t6WZbWonKJsHK0OoxH5S1Yoie4sSpw==", - "requires": { - "lodash": "^4.17.0", - "validator": "^3.33.0" - } - }, - "sanitizer": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/sanitizer/-/sanitizer-0.1.3.tgz", - "integrity": "sha1-1PCvdHXZp7ryqeWmEXGLqheKOeE=", - "dev": true - }, - "saslprep": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", - "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", - "optional": true, - "requires": { - "sparse-bitfield": "^3.0.3" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - } - } - }, - "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - } - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "sift": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz", - "integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g==" - }, - "sliced": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", - "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" - }, - "sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", - "optional": true, - "requires": { - "memory-pager": "^1.0.2" - } - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "streamsearch": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=", - "dev": true - }, - "string-sanitizer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string-sanitizer/-/string-sanitizer-1.1.1.tgz", - "integrity": "sha512-ZaqlidMholFiBaKDPPVf9cJjNo6iRhP6g/ei5qTgvzKEMa8TK/nu4hM90YZ2LvfjvAomF2LIexmOlX1MvYN+ug==", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "tga": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tga/-/tga-1.0.3.tgz", - "integrity": "sha1-fokbRRMIshi0gtvMna5nWWboIrM=", - "requires": { - "debug": "^2.6.1" - } - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" - }, - "topo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz", - "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==", - "dev": true, - "requires": { - "hoek": "6.x.x" - }, - "dependencies": { - "hoek": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", - "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==", - "dev": true - } - } - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "uid-safe": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", - "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", - "requires": { - "random-bytes": "~1.0.0" - } - }, - "universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==" - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - }, - "validator": { - "version": "3.43.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-3.43.0.tgz", - "integrity": "sha1-lkZLmS1BloM9l6GUv0Cxn/VLrgU=" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "xml2json": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/xml2json/-/xml2json-0.12.0.tgz", - "integrity": "sha512-EPJHRWJnJUYbJlzR4pBhZODwWdi2IaYGtDdteJi0JpZ4OD31IplWALuit8r73dJuM4iHZdDVKY1tLqY2UICejg==", - "dev": true, - "requires": { - "hoek": "^4.2.1", - "joi": "^13.1.2", - "node-expat": "^2.3.18" - } - }, - "xmlbuilder": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", - "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==" - }, - "xmlbuilder2": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-0.0.4.tgz", - "integrity": "sha512-4l+sSxet6EkVooCNlNgcImwrUZrk5BMRlJV6xUH9y19rwbwxB+OMfvlWT0hppDcVLjWM0Mu6FnpV/UGB4y/Feg==", - "requires": { - "@oozcitak/dom": "0.0.11", - "@oozcitak/infra": "1.0.4", - "@oozcitak/util": "1.0.3" - } - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - } - } + "name": "miiverse-api", + "version": "2.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "miiverse-api", + "version": "2.0.0", + "license": "AGPL-3.0", + "dependencies": { + "@pretendonetwork/grpc": "^1.0.3", + "aws-sdk": "^2.1204.0", + "colors": "^1.4.0", + "crc": "^4.3.2", + "dotenv": "^16.0.3", + "express": "^4.17.1", + "express-subdomain": "^1.0.5", + "fs-extra": "^9.0.0", + "moment": "^2.24.0", + "mongoose": "^6.10.1", + "morgan": "^1.10.0", + "multer": "^1.4.5-lts.1", + "nice-grpc": "^2.0.0", + "node-rsa": "^1.0.8", + "node-snowflake": "0.0.1", + "pako": "^1.0.11", + "pngjs": "^5.0.0", + "tga": "^1.0.3", + "xmlbuilder": "^15.1.1", + "zod": "^3.21.4" + }, + "devDependencies": { + "@types/express": "^4.17.17", + "@types/fs-extra": "^11.0.1", + "@types/morgan": "^1.9.4", + "@types/multer": "^1.4.7", + "@types/newman": "^5.3.4", + "@types/node-rsa": "^1.1.1", + "@types/pako": "^2.0.0", + "@types/pngjs": "^6.0.1", + "@typescript-eslint/eslint-plugin": "^5.59.0", + "@typescript-eslint/parser": "^5.59.0", + "axios": "^1.3.6", + "eslint": "^8.38.0", + "newman": "^6.0.0", + "ora": "^5.4.1", + "postman-collection": "^4.1.7", + "table": "^6.8.1", + "ts-unused-exports": "^9.0.4", + "tsc-alias": "^1.8.5", + "typescript": "^5.0.4", + "xmlbuilder2": "^3.1.0" + } + }, + "node_modules/@aws-crypto/crc32": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", + "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", + "optional": true, + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/crc32/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + }, + "node_modules/@aws-crypto/ie11-detection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", + "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", + "optional": true, + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", + "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", + "optional": true, + "dependencies": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", + "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", + "optional": true, + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-js/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", + "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", + "optional": true, + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + }, + "node_modules/@aws-crypto/util": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", + "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/util/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + }, + "node_modules/@aws-sdk/client-cognito-identity": { + "version": "3.421.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.421.0.tgz", + "integrity": "sha512-9htG14uDA/2XhU+vRhBcCG8GAOJ29rV53cxlc6I1YRKD6imXdU+X0ZfMPZCkPjEPGT4hHTpO0vR2J7zY8FXfzg==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.421.0", + "@aws-sdk/credential-provider-node": "3.421.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-signing": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/region-config-resolver": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/protocol-http": "^3.0.5", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.421.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.421.0.tgz", + "integrity": "sha512-40CmW7K2/FZEn3CbOjbpRYeVjKu6aJQlpRHcAgEJGNoVEAnRA3YNH4H0BN2iWWITfYg3B7sIjMm5VE9fCIK1Ng==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/region-config-resolver": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/protocol-http": "^3.0.5", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.421.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.421.0.tgz", + "integrity": "sha512-/92NOZMcdkBcvGrINk5B/l+6DGcVzYE4Ab3ME4vcY9y//u2gd0yNn5YYRSzzjVBLvhDP3u6CbTfLX2Bm4qihPw==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/credential-provider-node": "3.421.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-sdk-sts": "3.418.0", + "@aws-sdk/middleware-signing": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/region-config-resolver": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/protocol-http": "^3.0.5", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-cognito-identity": { + "version": "3.421.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.421.0.tgz", + "integrity": "sha512-x+C7nonKomdBAljTAPtqhU6Xzzaqy08PV1vO5Cp/YYMye+uOGQ2+1x7cfaY5uIHZbbNRUhCmUBKGnwsUyTB1cQ==", + "optional": true, + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.421.0", + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.418.0.tgz", + "integrity": "sha512-e74sS+x63EZUBO+HaI8zor886YdtmULzwKdctsZp5/37Xho1CVUNtEC+fYa69nigBD9afoiH33I4JggaHgrekQ==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.421.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.421.0.tgz", + "integrity": "sha512-J5yH/gkpAk6FMeH5F9u5Nr6oG+97tj1kkn5q49g3XMbtWw7GiynadxdtoRBCeIg1C7o2LOQx4B1AnhNhIw1z/g==", + "optional": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.418.0", + "@aws-sdk/credential-provider-process": "3.418.0", + "@aws-sdk/credential-provider-sso": "3.421.0", + "@aws-sdk/credential-provider-web-identity": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.421.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.421.0.tgz", + "integrity": "sha512-g1dvdvfDj0u8B/gOsHR3o1arP4O4QE/dFm2IJBYr/eUdKISMUgbQULWtg4zdtAf0Oz4xN0723i7fpXAF1gTnRA==", + "optional": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.418.0", + "@aws-sdk/credential-provider-ini": "3.421.0", + "@aws-sdk/credential-provider-process": "3.418.0", + "@aws-sdk/credential-provider-sso": "3.421.0", + "@aws-sdk/credential-provider-web-identity": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.418.0.tgz", + "integrity": "sha512-xPbdm2WKz1oH6pTkrJoUmr3OLuqvvcPYTQX0IIlc31tmDwDWPQjXGGFD/vwZGIZIkKaFpFxVMgAzfFScxox7dw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.421.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.421.0.tgz", + "integrity": "sha512-f8T3L5rhImL6T6RTSvbOxaWw9k2fDOT2DZbNjcPz9ITWmwXj2NNbdHGWuRi3dv2HoY/nW2IJdNxnhdhbn6Fc1A==", + "optional": true, + "dependencies": { + "@aws-sdk/client-sso": "3.421.0", + "@aws-sdk/token-providers": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.418.0.tgz", + "integrity": "sha512-do7ang565n9p3dS1JdsQY01rUfRx8vkxQqz5M8OlcEHBNiCdi2PvSjNwcBdrv/FKkyIxZb0TImOfBSt40hVdxQ==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers": { + "version": "3.421.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.421.0.tgz", + "integrity": "sha512-Mhz3r2N0YlOAhb1ZZYrP76VA1aIlJZw3IAwYwlS+hO4sAwp8iY6wCKiumqplXkVgK+ObLxlS9W/aW+2SAKsB7w==", + "optional": true, + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.421.0", + "@aws-sdk/client-sso": "3.421.0", + "@aws-sdk/client-sts": "3.421.0", + "@aws-sdk/credential-provider-cognito-identity": "3.421.0", + "@aws-sdk/credential-provider-env": "3.418.0", + "@aws-sdk/credential-provider-ini": "3.421.0", + "@aws-sdk/credential-provider-node": "3.421.0", + "@aws-sdk/credential-provider-process": "3.418.0", + "@aws-sdk/credential-provider-sso": "3.421.0", + "@aws-sdk/credential-provider-web-identity": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.418.0.tgz", + "integrity": "sha512-LrMTdzalkPw/1ujLCKPLwCGvPMCmT4P+vOZQRbSEVZPnlZk+Aj++aL/RaHou0jL4kJH3zl8iQepriBt4a7UvXQ==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.418.0.tgz", + "integrity": "sha512-StKGmyPVfoO/wdNTtKemYwoJsqIl4l7oqarQY7VSf2Mp3mqaa+njLViHsQbirYpyqpgUEusOnuTlH5utxJ1NsQ==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.418.0.tgz", + "integrity": "sha512-kKFrIQglBLUFPbHSDy1+bbe3Na2Kd70JSUC3QLMbUHmqipXN8KeXRfAj7vTv97zXl0WzG0buV++WcNwOm1rFjg==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-sts": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.418.0.tgz", + "integrity": "sha512-cW8ijrCTP+mgihvcq4+TbhAcE/we5lFl4ydRqvTdtcSnYQAVQADg47rnTScQiFsPFEB3NKq7BGeyTJF9MKolPA==", + "optional": true, + "dependencies": { + "@aws-sdk/middleware-signing": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.418.0.tgz", + "integrity": "sha512-onvs5KoYQE8OlOE740RxWBGtsUyVIgAo0CzRKOQO63ZEYqpL1Os+MS1CGzdNhvQnJgJruE1WW+Ix8fjN30zKPA==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.3.3", + "@smithy/util-middleware": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.418.0.tgz", + "integrity": "sha512-Jdcztg9Tal9SEAL0dKRrnpKrm6LFlWmAhvuwv0dQ7bNTJxIxyEFbpqdgy7mpQHsLVZgq1Aad/7gT/72c9igyZw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.418.0.tgz", + "integrity": "sha512-lJRZ/9TjZU6yLz+mAwxJkcJZ6BmyYoIJVo1p5+BN//EFdEmC8/c0c9gXMRzfISV/mqWSttdtccpAyN4/goHTYA==", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^2.0.12", + "@smithy/types": "^2.3.3", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.418.0.tgz", + "integrity": "sha512-9P7Q0VN0hEzTngy3Sz5eya2qEOEf0Q8qf1vB3um0gE6ID6EVAdz/nc/DztfN32MFxk8FeVBrCP5vWdoOzmd72g==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.418.0.tgz", + "integrity": "sha512-y4PQSH+ulfFLY0+FYkaK4qbIaQI9IJNMO2xsxukW6/aNoApNymN1D2FSi2la8Qbp/iPjNDKsG8suNPm9NtsWXQ==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.418.0.tgz", + "integrity": "sha512-sYSDwRTl7yE7LhHkPzemGzmIXFVHSsi3AQ1KeNEk84eBqxMHHcCc2kqklaBk2roXWe50QDgRMy1ikZUxvtzNHQ==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.418.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", + "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.418.0.tgz", + "integrity": "sha512-c4p4mc0VV/jIeNH0lsXzhJ1MpWRLuboGtNEpqE4s1Vl9ck2amv9VdUUZUmHbg+bVxlMgRQ4nmiovA4qIrqGuyg==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/types": "^2.3.3", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.418.0.tgz", + "integrity": "sha512-BXMskXFtg+dmzSCgmnWOffokxIbPr1lFqa1D9kvM3l3IFRiFGx2IyDg+8MAhq11aPDLvoa/BDuQ0Yqma5izOhg==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.5.1", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", + "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@faker-js/faker": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-5.5.3.tgz", + "integrity": "sha512-R11tGE6yIFwqpaIqcfkcg7AICXzFg14+5h5v0TfF/9+RMDL6jhzCy/pxHVOfbALGdtVYdt6JdR21tuxEgl34dw==", + "dev": true + }, + "node_modules/@grpc/grpc-js": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.14.tgz", + "integrity": "sha512-w84maJ6CKl5aApCMzFll0hxtFNT6or9WwMslobKaqWUEf1K+zhlL43bSQhFreyYWIWR+Z0xnVFC1KtLm4ZpM/A==", + "dependencies": { + "@grpc/proto-loader": "^0.7.0", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.6.tgz", + "integrity": "sha512-QyAXR8Hyh7uMDmveWxDSUcJr9NAWaZ2I6IXgAYvQmfflwouTM+rArE2eEaCtLlRqO81j7pRLCt81IefUei6Zbw==", + "dependencies": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^7.0.0", + "yargs": "^16.2.0" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz", + "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@oozcitak/dom": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-1.15.10.tgz", + "integrity": "sha512-0JT29/LaxVgRcGKvHmSrUTEvZ8BXvZhGl2LASRUgHqDTC1M5g1pLmVv56IYNyt3bG2CUjDkc67wnyZC14pbQrQ==", + "dev": true, + "dependencies": { + "@oozcitak/infra": "1.0.8", + "@oozcitak/url": "1.0.4", + "@oozcitak/util": "8.3.8" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/@oozcitak/infra": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-1.0.8.tgz", + "integrity": "sha512-JRAUc9VR6IGHOL7OGF+yrvs0LO8SlqGnPAMqyzOuFZPSZSXI7Xf2O9+awQPSMXgIWGtgUf/dA6Hs6X6ySEaWTg==", + "dev": true, + "dependencies": { + "@oozcitak/util": "8.3.8" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@oozcitak/url": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@oozcitak/url/-/url-1.0.4.tgz", + "integrity": "sha512-kDcD8y+y3FCSOvnBI6HJgl00viO/nGbQoCINmQ0h98OhnGITrWR3bOGfwYCthgcrV8AnTJz8MzslTQbC3SOAmw==", + "dev": true, + "dependencies": { + "@oozcitak/infra": "1.0.8", + "@oozcitak/util": "8.3.8" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/@oozcitak/util": { + "version": "8.3.8", + "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.3.8.tgz", + "integrity": "sha512-T8TbSnGsxo6TDBJx/Sgv/BlVJL3tshxZP7Aq5R1mSnM5OcHY2dQaxLMu2+E8u3gN0MLOzdjurqN4ZRVuzQycOQ==", + "dev": true, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/@postman/form-data": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@postman/form-data/-/form-data-3.1.1.tgz", + "integrity": "sha512-vjh8Q2a8S6UCm/KKs31XFJqEEgmbjBmpPNVV2eVav6905wyFAwaUOBGA1NPBI4ERH9MMZc6w0umFgM6WbEPMdg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@postman/tough-cookie": { + "version": "4.1.3-postman.1", + "resolved": "https://registry.npmjs.org/@postman/tough-cookie/-/tough-cookie-4.1.3-postman.1.tgz", + "integrity": "sha512-txpgUqZOnWYnUHZpHjkfb0IwVH4qJmyq77pPnJLlfhMtdCLMFTEeQHlzQiK906aaNCe4NEB5fGJHo9uzGbFMeA==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@postman/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/@postman/tunnel-agent": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@postman/tunnel-agent/-/tunnel-agent-0.6.3.tgz", + "integrity": "sha512-k57fzmAZ2PJGxfOA4SGR05ejorHbVAa/84Hxh/2nAztjNXc4ZjOm9NUIk6/Z6LCrBvJZqjRZbN8e/nROVUPVdg==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@pretendonetwork/grpc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@pretendonetwork/grpc/-/grpc-1.0.3.tgz", + "integrity": "sha512-NlfzonmHqNRUDuc1nCON6u3f6II3KtSQgs7g5u4TEG8KKIIvBWKQT3mWVsRIkBEEpPdtad/dwASVzIR7lymKWw==", + "dependencies": { + "long": "^5.2.1", + "protobufjs": "^7.2.3" + } + }, + "node_modules/@pretendonetwork/grpc/node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, + "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/@smithy/abort-controller": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.10.tgz", + "integrity": "sha512-xn7PnFD3m4rQIG00h1lPuDVnC2QMtTFhzRLX3y56KkgFaCysS7vpNevNBgmNUtmJ4eVFc+66Zucwo2KDLdicOg==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.11.tgz", + "integrity": "sha512-q97FnlUmbai1c4JlQJgLVBsvSxgV/7Nvg/JK76E1nRq/U5UM56Eqo3dn2fY7JibqgJLg4LPsGdwtIyqyOk35CQ==", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^2.0.13", + "@smithy/types": "^2.3.4", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.13.tgz", + "integrity": "sha512-/xe3wNoC4j+BeTemH9t2gSKLBfyZmk8LXB2pQm/TOEYi+QhBgT+PSolNDfNAhrR68eggNE17uOimsrnwSkCt4w==", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^2.0.13", + "@smithy/property-provider": "^2.0.11", + "@smithy/types": "^2.3.4", + "@smithy/url-parser": "^2.0.10", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-codec": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.10.tgz", + "integrity": "sha512-3SSDgX2nIsFwif6m+I4+ar4KDcZX463Noes8ekBgQHitULiWvaDZX8XqPaRQSQ4bl1vbeVXHklJfv66MnVO+lw==", + "optional": true, + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@smithy/types": "^2.3.4", + "@smithy/util-hex-encoding": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.2.0.tgz", + "integrity": "sha512-P2808PM0CsEkXj3rnQAi3QyqRbAAi8iuePYUB5GveJ+dVd1WMv03NM+CYCI14IGXt1j/r7jHGvMJHO+Gv+kdMQ==", + "optional": true, + "dependencies": { + "@smithy/protocol-http": "^3.0.6", + "@smithy/querystring-builder": "^2.0.10", + "@smithy/types": "^2.3.4", + "@smithy/util-base64": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.10.tgz", + "integrity": "sha512-jSTf6uzPk/Vf+8aQ7tVXeHfjxe9wRXSCqIZcBymSDTf7/YrVxniBdpyN74iI8ZUOx/Pyagc81OK5FROLaEjbXQ==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.3.4", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.10.tgz", + "integrity": "sha512-zw9p/zsmJ2cFcW4KMz3CJoznlbRvEA6HG2mvEaX5eAca5dq4VGI2MwPDTfmteC/GsnURS4ogoMQ0p6aHM2SDVQ==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz", + "integrity": "sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.12.tgz", + "integrity": "sha512-QRhJTo5TjG7oF7np6yY4ZO9GDKFVzU/GtcqUqyEa96bLHE3yZHgNmsolOQ97pfxPHmFhH4vDP//PdpAIN3uI1Q==", + "optional": true, + "dependencies": { + "@smithy/protocol-http": "^3.0.6", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.10.tgz", + "integrity": "sha512-O6m4puZc16xfenotZUHL4bRlMrwf4gTp+0I5l954M5KNd3dOK18P+FA/IIUgnXF/dX6hlCUcJkBp7nAzwrePKA==", + "optional": true, + "dependencies": { + "@smithy/middleware-serde": "^2.0.10", + "@smithy/types": "^2.3.4", + "@smithy/url-parser": "^2.0.10", + "@smithy/util-middleware": "^2.0.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.13.tgz", + "integrity": "sha512-zuOva8xgWC7KYG8rEXyWIcZv2GWszO83DCTU6IKcf/FKu6OBmSE+EYv3EUcCGY+GfiwCX0EyJExC9Lpq9b0w5Q==", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^2.0.13", + "@smithy/protocol-http": "^3.0.6", + "@smithy/service-error-classification": "^2.0.3", + "@smithy/types": "^2.3.4", + "@smithy/util-middleware": "^2.0.3", + "@smithy/util-retry": "^2.0.3", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "optional": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.10.tgz", + "integrity": "sha512-+A0AFqs768256H/BhVEsBF6HijFbVyAwYRVXY/izJFkTalVWJOp4JA0YdY0dpXQd+AlW0tzs+nMQCE1Ew+DcgQ==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.4.tgz", + "integrity": "sha512-MW0KNKfh8ZGLagMZnxcLJWPNXoKqW6XV/st5NnCBmmA2e2JhrUjU0AJ5Ca/yjTyNEKs3xH7AQDwp1YmmpEpmQQ==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.0.13.tgz", + "integrity": "sha512-pPpLqYuJcOq1sj1EGu+DoZK47DUS4gepqSTNgRezmrjnzNlSU2/Dcc9Ebzs+WZ0Z5vXKazuE+k+NksFLo07/AA==", + "optional": true, + "dependencies": { + "@smithy/property-provider": "^2.0.11", + "@smithy/shared-ini-file-loader": "^2.0.12", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.1.6.tgz", + "integrity": "sha512-NspvD3aCwiUNtoSTcVHz0RZz1tQ/SaRIe1KPF+r0mAdCZ9eWuhIeJT8ZNPYa1ITn7/Lgg64IyFjqPynZ8KnYQw==", + "optional": true, + "dependencies": { + "@smithy/abort-controller": "^2.0.10", + "@smithy/protocol-http": "^3.0.6", + "@smithy/querystring-builder": "^2.0.10", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.11.tgz", + "integrity": "sha512-kzuOadu6XvrnlF1iXofpKXYmo4oe19st9/DE8f5gHNaFepb4eTkR8gD8BSdTnNnv7lxfv6uOwZPg4VS6hemX1w==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.6.tgz", + "integrity": "sha512-F0jAZzwznMmHaggiZgc7YoS08eGpmLvhVktY/Taz6+OAOHfyIqWSDNgFqYR+WHW9z5fp2XvY4mEUrQgYMQ71jw==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.10.tgz", + "integrity": "sha512-uujJGp8jzrrU1UHme8sUKEbawQTcTmUWsh8rbGXYD/lMwNLQ+9jQ9dMDWbbH9Hpoa9RER1BeL/38WzGrbpob2w==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.3.4", + "@smithy/util-uri-escape": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.10.tgz", + "integrity": "sha512-WSD4EU60Q8scacT5PIpx4Bahn6nWpt+MiYLcBkFt6fOj7AssrNeaNIU2Z0g40ftVmrwLcEOIKGX92ynbVDb3ZA==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.3.tgz", + "integrity": "sha512-b+m4QCHXb7oKAkM/jHwHrl5gpqhFoMTHF643L0/vAEkegrcUWyh1UjyoHttuHcP5FnHVVy4EtpPtLkEYD+xMFw==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.3.4" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.0.12.tgz", + "integrity": "sha512-umi0wc4UBGYullAgYNUVfGLgVpxQyES47cnomTqzCKeKO5oudO4hyDNj+wzrOjqDFwK2nWYGVgS8Y0JgGietrw==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.10.tgz", + "integrity": "sha512-S6gcP4IXfO/VMswovrhxPpqvQvMal7ZRjM4NvblHSPpE5aNBYx67UkHFF3kg0hR3tJKqNpBGbxwq0gzpdHKLRA==", + "optional": true, + "dependencies": { + "@smithy/eventstream-codec": "^2.0.10", + "@smithy/is-array-buffer": "^2.0.0", + "@smithy/types": "^2.3.4", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-middleware": "^2.0.3", + "@smithy/util-uri-escape": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.1.8.tgz", + "integrity": "sha512-Puuc4wuhdTSs8wstkNJ/JtpaFwIh0qDE27zawfRVzzjpXprpT+4wROqO2+NVoZ+6GKv7kz7QgZx6AI5325bSeQ==", + "optional": true, + "dependencies": { + "@smithy/middleware-stack": "^2.0.4", + "@smithy/types": "^2.3.4", + "@smithy/util-stream": "^2.0.13", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.3.4.tgz", + "integrity": "sha512-D7xlM9FOMFyFw7YnMXn9dK2KuN6+JhnrZwVt1fWaIu8hCk5CigysweeIT/H/nCo4YV+s8/oqUdLfexbkPZtvqw==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.10.tgz", + "integrity": "sha512-4TXQFGjHcqru8aH5VRB4dSnOFKCYNX6SR1Do6fwxZ+ExT2onLsh2W77cHpks7ma26W5jv6rI1u7d0+KX9F0aOw==", + "optional": true, + "dependencies": { + "@smithy/querystring-parser": "^2.0.10", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.0.tgz", + "integrity": "sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA==", + "optional": true, + "dependencies": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz", + "integrity": "sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz", + "integrity": "sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz", + "integrity": "sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==", + "optional": true, + "dependencies": { + "@smithy/is-array-buffer": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz", + "integrity": "sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.12.tgz", + "integrity": "sha512-BCsFPdNThMS2312/Zj3/TtFsXfO2BwkbDNsoWbdtZ0cAv9cE6vqGKllYXmq2Gj6u+Vv8V3wUgBUicNol6s/7Sg==", + "optional": true, + "dependencies": { + "@smithy/property-provider": "^2.0.11", + "@smithy/smithy-client": "^2.1.8", + "@smithy/types": "^2.3.4", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.14.tgz", + "integrity": "sha512-EtomtYsWDkBGs0fLeF+7N2df+zIqGix+O4llWqQD+97rbo2hk+GBWeZzBkujKrzFeXNUbPkFqfvZPLdoq4S4XQ==", + "optional": true, + "dependencies": { + "@smithy/config-resolver": "^2.0.11", + "@smithy/credential-provider-imds": "^2.0.13", + "@smithy/node-config-provider": "^2.0.13", + "@smithy/property-provider": "^2.0.11", + "@smithy/smithy-client": "^2.1.8", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz", + "integrity": "sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.3.tgz", + "integrity": "sha512-+FOCFYOxd2HO7v/0hkFSETKf7FYQWa08wh/x/4KUeoVBnLR4juw8Qi+TTqZI6E2h5LkzD9uOaxC9lAjrpVzaaA==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.3.tgz", + "integrity": "sha512-gw+czMnj82i+EaH7NL7XKkfX/ZKrCS2DIWwJFPKs76bMgkhf0y1C94Lybn7f8GkBI9lfIOUdPYtzm19zQOC8sw==", + "optional": true, + "dependencies": { + "@smithy/service-error-classification": "^2.0.3", + "@smithy/types": "^2.3.4", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.13.tgz", + "integrity": "sha512-aeua6pN0WMdQtZNRRJ8J+mop57fezLMsApYbk5Q3q11pyHwZypVPuKoelr7K9PMJZcuYk90dQyUsUAd7hTCeRg==", + "optional": true, + "dependencies": { + "@smithy/fetch-http-handler": "^2.2.0", + "@smithy/node-http-handler": "^2.1.6", + "@smithy/types": "^2.3.4", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz", + "integrity": "sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.0.tgz", + "integrity": "sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ==", + "optional": true, + "dependencies": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.34", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz", + "integrity": "sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/fs-extra": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.1.tgz", + "integrity": "sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==", + "dev": true, + "dependencies": { + "@types/jsonfile": "*", + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/jsonfile": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.1.tgz", + "integrity": "sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "node_modules/@types/morgan": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", + "integrity": "sha512-cXoc4k+6+YAllH3ZHmx4hf7La1dzUk6keTR4bF4b4Sc0mZxU/zK4wO7l+ZzezXm/jkYj/qC+uYGZrarZdIVvyQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/multer": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", + "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/newman": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/@types/newman/-/newman-5.3.4.tgz", + "integrity": "sha512-Y6qFSbUwTm0UwCEXl97Q2cNCXYX+N5vFMw80opp8z6Du0mzM01y/Uku6csYkhqS0yMaRDwgq2JYTUNYnbR6Y1A==", + "dev": true, + "dependencies": { + "@types/postman-collection": "*", + "@types/tough-cookie": "*" + } + }, + "node_modules/@types/node": { + "version": "18.16.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz", + "integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==" + }, + "node_modules/@types/node-rsa": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/node-rsa/-/node-rsa-1.1.1.tgz", + "integrity": "sha512-itzxtaBgk4OMbrCawVCvas934waMZWjW17v7EYgFVlfYS/cl0/P7KZdojWCq9SDJMI5cnLQLUP8ayhVCTY8TEg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/pako": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.0.tgz", + "integrity": "sha512-10+iaz93qR5WYxTo+PMifD5TSxiOtdRaxBf7INGGXMQgTCu8Z/7GYWYFUOS3q/G0nE5boj1r4FEB+WSy7s5gbA==", + "dev": true + }, + "node_modules/@types/pngjs": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/pngjs/-/pngjs-6.0.1.tgz", + "integrity": "sha512-J39njbdW1U/6YyVXvC9+1iflZghP8jgRf2ndYghdJb5xL49LYDB+1EuAxfbuJ2IBbWIL3AjHPQhgaTxT3YaYeg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/postman-collection": { + "version": "3.5.8", + "resolved": "https://registry.npmjs.org/@types/postman-collection/-/postman-collection-3.5.8.tgz", + "integrity": "sha512-WhApDX/dQtFR5rygj+M+AcRp750wZ9JO5iw289aQIzA6Z+GZd7YDbA/aI4mx+yQrlUKpzgiE0zWEZbnzxup2WA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", + "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "dev": true, + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.3.tgz", + "integrity": "sha512-THo502dA5PzG/sfQH+42Lw3fvmYkceefOspdCwpHRul8ik2Jv1K8I5OZz1AT3/rs46kwgMCe9bSBmDLYkkOMGg==", + "dev": true + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.1.tgz", + "integrity": "sha512-8hKOnOan+Uu+NgMaCouhg3cT9x5fFZ92Jwf+uDLXLu/MFRbXxlWwGeQY7KVHkeSft6RvY+tdxklUBuyY9eIEKg==" + }, + "node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.2.tgz", + "integrity": "sha512-yVrXupeHjRxLDcPKL10sGQ/QlVrA8J5IYOEWVqk0lJaSZP7X5DfnP7Ns3cc74/blmbipQ1htFNVGsHX6wsYm0A==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.59.2", + "@typescript-eslint/type-utils": "5.59.2", + "@typescript-eslint/utils": "5.59.2", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.2.tgz", + "integrity": "sha512-uq0sKyw6ao1iFOZZGk9F8Nro/8+gfB5ezl1cA06SrqbgJAt0SRoFhb9pXaHvkrxUpZaoLxt8KlovHNk8Gp6/HQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.59.2", + "@typescript-eslint/types": "5.59.2", + "@typescript-eslint/typescript-estree": "5.59.2", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.2.tgz", + "integrity": "sha512-dB1v7ROySwQWKqQ8rEWcdbTsFjh2G0vn8KUyvTXdPoyzSL6lLGkiXEV5CvpJsEe9xIdKV+8Zqb7wif2issoOFA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.59.2", + "@typescript-eslint/visitor-keys": "5.59.2" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz", + "integrity": "sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.59.2", + "@typescript-eslint/utils": "5.59.2", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.2.tgz", + "integrity": "sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz", + "integrity": "sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.59.2", + "@typescript-eslint/visitor-keys": "5.59.2", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.2.tgz", + "integrity": "sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.59.2", + "@typescript-eslint/types": "5.59.2", + "@typescript-eslint/typescript-estree": "5.59.2", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.59.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz", + "integrity": "sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.59.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/abort-controller-x": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/abort-controller-x/-/abort-controller-x-0.4.1.tgz", + "integrity": "sha512-lJ2ssrl3FoTK3cX/g15lRCkXFWKiwRTRtBjfwounO2EM/Q65rI/MEZsfsch1juWU2pH2aLSaq0HGowlDP/imrw==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "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/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "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": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sdk": { + "version": "2.1369.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1369.0.tgz", + "integrity": "sha512-DdCQjlhQDi9w8J4moqECrrp9ARWCay0UI38adPSS0GG43gh3bl3OoMlgKJ8aZxi4jUvzE48K9yhFHz4y/mazZw==", + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-sdk/node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "dev": true + }, + "node_modules/axios": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "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 + }, + "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", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "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/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bluebird": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha512-UfFSr22dmHPQqPP9XWHRhq+gWnHCYguQGkXQlbyPtW5qTnhFWA8/iXg765tH0cAjy7l/zPJ1aBTO0g5XgA7kvQ==", + "dev": true + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", + "optional": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "dev": true, + "dependencies": { + "base64-js": "^1.1.2" + } + }, + "node_modules/bson": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", + "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", + "dependencies": { + "buffer": "^5.6.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/bson/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": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true, + "peer": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/buffer/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" + } + ], + "optional": true, + "peer": true + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-1.6.0.tgz", + "integrity": "sha512-+QOTw3otC4+FxdjK9RopGpNOglADbr4WPFi0SonkO99JbpkTPbMxmdm4NenhF5Zs+4gPXLI1+y2uazws5TMe8w==", + "dev": true + }, + "node_modules/charset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/charset/-/charset-1.0.1.tgz", + "integrity": "sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-progress": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", + "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", + "dev": true, + "dependencies": { + "string-width": "^4.2.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-spinners": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.8.0.tgz", + "integrity": "sha512-/eG5sJcvEIwxcdYM86k5tPwn0MUzkX5YY3eImTGpJOZgVe4SdTMY14vQpcxgBzJ0wXwAYrS8E+c3uHeK4JNyzQ==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "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==" + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", + "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "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 + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/crc": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/crc/-/crc-4.3.2.tgz", + "integrity": "sha512-uGDHf4KLLh2zsHa8D8hIQ1H/HtFQhyHrc0uhHBcoKGol/Xnb+MPYfUMw7cvON6ze/GUESTudKayDcJC5HnJv1A==", + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "buffer": ">=6.0.3" + }, + "peerDependenciesMeta": { + "buffer": { + "optional": true + } + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csv-parse": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", + "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", + "dev": true + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "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/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", + "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.39.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express-subdomain": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/express-subdomain/-/express-subdomain-1.0.5.tgz", + "integrity": "sha512-tpYy7MPgDoouxA4r+BnGI43yxYakbSSpQn7MjEYM0ssHeipTM1YiIoK3i4pCAgoXoks22Yb5C4QFkOYBYczZcw==" + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-xml-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", + "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", + "funding": [ + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + }, + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "optional": true, + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/filesize": { + "version": "10.0.12", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-10.0.12.tgz", + "integrity": "sha512-6RS9gDchbn+qWmtV2uSjo5vmKizgfCQeb5jKmqx8HyzA3MoLqqyQxN+QcjkGBJt7FjJ9qFce67Auyya5rRRbpw==", + "dev": true, + "engines": { + "node": ">= 10.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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 + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "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/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-reasons": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/http-reasons/-/http-reasons-0.1.0.tgz", + "integrity": "sha512-P6kYh0lKZ+y29T2Gqz+RlC9WBLhKe8kDmcJ+A+611jFfxdPsbMRQ5aNmFRM3lENqFkK+HTTL+tlQviAiv0AbLQ==", + "dev": true + }, + "node_modules/http-signature": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/httpntlm": { + "version": "1.8.13", + "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.8.13.tgz", + "integrity": "sha512-2F2FDPiWT4rewPzNMg3uPhNkP3NExENlUGADRUDPQvuftuUTGW98nLZtGemCIW3G40VhWZYgkIDcQFAwZ3mf2Q==", + "dev": true, + "funding": [ + { + "type": "paypal", + "url": "https://www.paypal.com/donate/?hosted_button_id=2CKNJLZJBW8ZC" + }, + { + "type": "buymeacoffee", + "url": "https://www.buymeacoffee.com/samdecrock" + } + ], + "dependencies": { + "des.js": "^1.0.1", + "httpreq": ">=0.4.22", + "js-md4": "^0.3.2", + "underscore": "~1.12.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/httpreq": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-1.1.1.tgz", + "integrity": "sha512-uhSZLPPD2VXXOSN8Cni3kIsoFHaU2pT/nySEU/fHr/ePbqHYr0jeiQRmUKLEirC09SFPsdMoA7LU7UXMd/w0Kw==", + "dev": true, + "engines": { + "node": ">= 6.15.1" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "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/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/jose": { + "version": "4.14.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", + "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-md4": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", + "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==", + "dev": true + }, + "node_modules/js-sdsl": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-sha512": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz", + "integrity": "sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "node_modules/kareem": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", + "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/liquid-json": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/liquid-json/-/liquid-json-0.3.1.tgz", + "integrity": "sha512-wUayTU8MS827Dam6MxgD72Ui+KOSF+u/eIqpatOtjnvgJ0+mnDq33uC2M7J0tPK+upe/DpUAuK4JUU89iBoNKQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "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.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "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": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-format": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mime-format/-/mime-format-2.0.1.tgz", + "integrity": "sha512-XxU3ngPbEnrYnNbIX+lYSaYg0M01v6p2ntd2YaFksTu0vayaw5OJvbdRyWs07EYRlLED5qadUZ+xo+XhOvFhwg==", + "dev": true, + "dependencies": { + "charset": "^1.0.0" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, + "node_modules/mongodb": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.17.1.tgz", + "integrity": "sha512-MBuyYiPUPRTqfH2dV0ya4dcr2E5N52ocBuZ8Sgg/M030nGF78v855B3Z27mZJnp8PxjnUquEnAtjOsphgMZOlQ==", + "dependencies": { + "bson": "^4.7.2", + "mongodb-connection-string-url": "^2.6.0", + "socks": "^2.7.1" + }, + "engines": { + "node": ">=12.9.0" + }, + "optionalDependencies": { + "@aws-sdk/credential-providers": "^3.186.0", + "@mongodb-js/saslprep": "^1.1.0" + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/mongoose": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.12.0.tgz", + "integrity": "sha512-sd/q83C6TBRPBrrD2A/POSbA/exbCFM2WOuY7Lf2JuIJFlHFG39zYSDTTAEiYlzIfahNOLmXPxBGFxdAch41Mw==", + "dependencies": { + "bson": "^4.7.2", + "kareem": "2.5.1", + "mongodb": "4.17.1", + "mpath": "0.9.0", + "mquery": "4.0.3", + "ms": "2.1.3", + "sift": "16.0.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mongoose/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/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/morgan/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz", + "integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==", + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "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==" + }, + "node_modules/multer": { + "version": "1.4.5-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", + "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/mylas": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/mylas/-/mylas-2.1.13.tgz", + "integrity": "sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/raouldeheer" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/newman": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/newman/-/newman-6.0.0.tgz", + "integrity": "sha512-QaANQC5b6ga348MezIVRI9ZmMs+cg3MdYIp0tSEauH2tmWOAR9+cghNsFJNjU9JPui3jJp1ALC7pQq6g3Jqpxw==", + "dev": true, + "dependencies": { + "@postman/tough-cookie": "4.1.3-postman.1", + "async": "3.2.4", + "chardet": "1.6.0", + "cli-progress": "3.12.0", + "cli-table3": "0.6.3", + "colors": "1.4.0", + "commander": "11.0.0", + "csv-parse": "4.16.3", + "filesize": "10.0.12", + "liquid-json": "0.3.1", + "lodash": "4.17.21", + "mkdirp": "3.0.1", + "postman-collection": "4.2.1", + "postman-collection-transformer": "4.1.7", + "postman-request": "2.88.1-postman.33", + "postman-runtime": "7.33.0", + "pretty-ms": "7.0.1", + "semver": "7.5.4", + "serialised-error": "1.1.3", + "word-wrap": "1.2.5", + "xmlbuilder": "15.1.1" + }, + "bin": { + "newman": "bin/newman.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/newman/node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nice-grpc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/nice-grpc/-/nice-grpc-2.1.4.tgz", + "integrity": "sha512-ZCSnFxg/k6PM1zZ2u/SbuySTrpK7q4klwRE4ymAdiMfZM3Rl1LRUdqUslKSbSjd9XQHzi80Y5JJL5fE58lSrVA==", + "dependencies": { + "@grpc/grpc-js": "^1.7.3", + "abort-controller-x": "^0.4.0", + "nice-grpc-common": "^2.0.2" + } + }, + "node_modules/nice-grpc-common": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/nice-grpc-common/-/nice-grpc-common-2.0.2.tgz", + "integrity": "sha512-7RNWbls5kAL1QVUOXvBsv1uO0wPQK3lHv+cY1gwkTzirnG1Nop4cBJZubpgziNbaVc/bl9QJcyvsf/NQxa3rjQ==", + "dependencies": { + "ts-error": "^1.0.6" + } + }, + "node_modules/node-oauth1": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/node-oauth1/-/node-oauth1-1.3.0.tgz", + "integrity": "sha512-0yggixNfrA1KcBwvh/Hy2xAS1Wfs9dcg6TdFf2zN7gilcAigMdrtZ4ybrBSXBgLvGDw9V1p2MRnGBMq7XjTWLg==", + "dev": true + }, + "node_modules/node-rsa": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-1.1.1.tgz", + "integrity": "sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw==", + "dependencies": { + "asn1": "^0.2.4" + } + }, + "node_modules/node-snowflake": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/node-snowflake/-/node-snowflake-0.0.1.tgz", + "integrity": "sha512-QU1jPDI+vFN3ANBnDafDdzwniLfw/STYsSQ1wpKmBD5xFv7jGPX2ItcHYiomVw3KRHno/MHqu0G1nddpwdZ/OA==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", + "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "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" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/plimit-lit": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/plimit-lit/-/plimit-lit-1.5.0.tgz", + "integrity": "sha512-Eb/MqCb1Iv/ok4m1FqIXqvUKPISufcjZ605hl3KM/n8GaX8zfhtgdLwZU3vKjuHGh2O9Rjog/bHTq8ofIShdng==", + "dev": true, + "dependencies": { + "queue-lit": "^1.5.0" + } + }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/postman-collection": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.2.1.tgz", + "integrity": "sha512-DFLt3/yu8+ldtOTIzmBUctoupKJBOVK4NZO0t68K2lIir9smQg7OdQTBjOXYy+PDh7u0pSDvD66tm93eBHEPHA==", + "dev": true, + "dependencies": { + "@faker-js/faker": "5.5.3", + "file-type": "3.9.0", + "http-reasons": "0.1.0", + "iconv-lite": "0.6.3", + "liquid-json": "0.3.1", + "lodash": "4.17.21", + "mime-format": "2.0.1", + "mime-types": "2.1.35", + "postman-url-encoder": "3.0.5", + "semver": "7.5.4", + "uuid": "8.3.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postman-collection-transformer": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/postman-collection-transformer/-/postman-collection-transformer-4.1.7.tgz", + "integrity": "sha512-SxJkm/LnlFZs2splUBnS4jQFicgBptghpm4voHtNnaum3Ad64E2MHLV4fJhv58dVUmFwdSwdQUN3m2q0iLecnQ==", + "dev": true, + "dependencies": { + "commander": "8.3.0", + "inherits": "2.0.4", + "lodash": "4.17.21", + "semver": "7.5.4", + "strip-json-comments": "3.1.1" + }, + "bin": { + "postman-collection-transformer": "bin/transform-collection.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postman-collection-transformer/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/postman-collection/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postman-collection/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/postman-request": { + "version": "2.88.1-postman.33", + "resolved": "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.33.tgz", + "integrity": "sha512-uL9sCML4gPH6Z4hreDWbeinKU0p0Ke261nU7OvII95NU22HN6Dk7T/SaVPaj6T4TsQqGKIFw6/woLZnH7ugFNA==", + "dev": true, + "dependencies": { + "@postman/form-data": "~3.1.1", + "@postman/tough-cookie": "~4.1.3-postman.1", + "@postman/tunnel-agent": "^0.6.3", + "aws-sign2": "~0.7.0", + "aws4": "^1.12.0", + "brotli": "^1.3.3", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "har-validator": "~5.1.3", + "http-signature": "~1.3.1", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "^2.1.35", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.3", + "safe-buffer": "^5.1.2", + "stream-length": "^1.0.2", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postman-request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/postman-request/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/postman-runtime": { + "version": "7.33.0", + "resolved": "https://registry.npmjs.org/postman-runtime/-/postman-runtime-7.33.0.tgz", + "integrity": "sha512-cYCb+5Y12FwZU/T3gOj2SKiOz38pisVLc0tdppb+ZlG7iqn5aLgxghJwhjG62pZCV6uixKiQX1hNdLSk9a9Xtw==", + "dev": true, + "dependencies": { + "@postman/tough-cookie": "4.1.3-postman.1", + "async": "3.2.4", + "aws4": "1.12.0", + "handlebars": "4.7.8", + "httpntlm": "1.8.13", + "jose": "4.14.4", + "js-sha512": "0.8.0", + "lodash": "4.17.21", + "mime-types": "2.1.35", + "node-oauth1": "1.3.0", + "performance-now": "2.1.0", + "postman-collection": "4.2.0", + "postman-request": "2.88.1-postman.33", + "postman-sandbox": "4.2.7", + "postman-url-encoder": "3.0.5", + "serialised-error": "1.1.3", + "strip-json-comments": "3.1.1", + "uuid": "8.3.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/postman-runtime/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postman-runtime/node_modules/postman-collection": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.2.0.tgz", + "integrity": "sha512-tvOLgN1h6Kab6dt43PmBoV5kYO/YUta3x0C2QqfmbzmHZe47VTpZ/+gIkGlbNhjKNPUUub5X6ehxYKoaTYdy1w==", + "dev": true, + "dependencies": { + "@faker-js/faker": "5.5.3", + "file-type": "3.9.0", + "http-reasons": "0.1.0", + "iconv-lite": "0.6.3", + "liquid-json": "0.3.1", + "lodash": "4.17.21", + "mime-format": "2.0.1", + "mime-types": "2.1.35", + "postman-url-encoder": "3.0.5", + "semver": "7.5.4", + "uuid": "8.3.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postman-runtime/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/postman-sandbox": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/postman-sandbox/-/postman-sandbox-4.2.7.tgz", + "integrity": "sha512-/EcCrKnb/o+9iLS4u+H76E0kBomJFjPptVjoDiq1uZ7Es/4aTv0MAX+0aoDxdDO+0h9sl8vy65uKQwyjN7AOaw==", + "dev": true, + "dependencies": { + "lodash": "4.17.21", + "postman-collection": "4.2.0", + "teleport-javascript": "1.0.0", + "uvm": "2.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postman-sandbox/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postman-sandbox/node_modules/postman-collection": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.2.0.tgz", + "integrity": "sha512-tvOLgN1h6Kab6dt43PmBoV5kYO/YUta3x0C2QqfmbzmHZe47VTpZ/+gIkGlbNhjKNPUUub5X6ehxYKoaTYdy1w==", + "dev": true, + "dependencies": { + "@faker-js/faker": "5.5.3", + "file-type": "3.9.0", + "http-reasons": "0.1.0", + "iconv-lite": "0.6.3", + "liquid-json": "0.3.1", + "lodash": "4.17.21", + "mime-format": "2.0.1", + "mime-types": "2.1.35", + "postman-url-encoder": "3.0.5", + "semver": "7.5.4", + "uuid": "8.3.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postman-sandbox/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/postman-url-encoder": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postman-url-encoder/-/postman-url-encoder-3.0.5.tgz", + "integrity": "sha512-jOrdVvzUXBC7C+9gkIkpDJ3HIxOHTIqjpQ4C1EMt1ZGeMvSEpbFCKq23DEfgsj46vMnDgyQf+1ZLp2Wm+bKSsA==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-ms": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", + "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", + "dev": true, + "dependencies": { + "parse-ms": "^2.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/protobufjs": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", + "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/protobufjs/node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "node_modules/queue-lit": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/queue-lit/-/queue-lit-1.5.0.tgz", + "integrity": "sha512-IslToJ4eiCEE9xwMzq3viOO5nH8sUWUCwoElrhNMozzr9IIt2qqvB4I+uHu/zJTQVqc9R5DFwok4ijNK1pU3fA==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "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/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "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==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restructure": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/restructure/-/restructure-2.0.1.tgz", + "integrity": "sha512-e0dOpjm5DseomnXx2M5lpdZ5zoHqF1+bqdMJUohoYVVQa7cBdnk7fdmeI6byNWP/kiME72EeTiSypTCVnpLiDg==" + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "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": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/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/serialised-error": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/serialised-error/-/serialised-error-1.1.3.tgz", + "integrity": "sha512-vybp3GItaR1ZtO2nxZZo8eOo7fnVaNtP3XE2vJKgzkKR2bagCkdJ1EpYYhEMd3qu/80DwQk9KjsNSxE3fXWq0g==", + "dev": true, + "dependencies": { + "object-hash": "^1.1.2", + "stack-trace": "0.0.9", + "uuid": "^3.0.0" + } + }, + "node_modules/serialised-error/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sift": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", + "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" + }, + "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==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "optional": true, + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", + "integrity": "sha512-vjUc6sfgtgY0dxCdnc40mK6Oftjo9+2K8H/NG81TMhgL392FtiPA9tn9RLyTxXmTLPJPjF3VyzFp6bsWFLisMQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stream-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-length/-/stream-length-1.0.2.tgz", + "integrity": "sha512-aI+qKFiwoDV4rsXiS7WRoCt+v2RX1nUj17+KJC5r2gfh5xoSJIfP6Y3Do/HtvesFcTSWthIuJ3l1cvKQY/+nZg==", + "dev": true, + "dependencies": { + "bluebird": "^2.6.2" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "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/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/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "optional": true + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/table": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/teleport-javascript": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/teleport-javascript/-/teleport-javascript-1.0.0.tgz", + "integrity": "sha512-j1llvWVFyEn/6XIFDfX5LAU43DXe0GCt3NfXDwJ8XpRRMkS+i50SAkonAONBy+vxwPFBd50MFU8a2uj8R/ccLg==", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/tga": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tga/-/tga-1.0.7.tgz", + "integrity": "sha512-GFVJwov5aJTMgh8U1QfaRheIELXo+dYc1qYIvQEIqZX4n+S6Fj/SDWsdbelHt7WP08xOR6W1z5aJQ+Ilh5gIeA==", + "dependencies": { + "debug": "^2.6.1", + "restructure": "^2.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/tga/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/tga/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ts-error": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/ts-error/-/ts-error-1.0.6.tgz", + "integrity": "sha512-tLJxacIQUM82IR7JO1UUkKlYuUTmoY9HBJAmNWFzheSlDS5SPMcNIepejHJa4BpPQLAcbRhRf3GDJzyj6rbKvA==" + }, + "node_modules/ts-unused-exports": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/ts-unused-exports/-/ts-unused-exports-9.0.4.tgz", + "integrity": "sha512-/PPy0B1zhOJkDTUd1XVyaCqE/yA3IL2FrQ8W5/6cQ2g0kKC/06q8LEoPeXI6ELfI6Bivmv3MMvsUup5u3WH+BQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "tsconfig-paths": "^3.9.0" + }, + "bin": { + "ts-unused-exports": "bin/ts-unused-exports" + }, + "funding": { + "url": "https://github.com/pzavolinsky/ts-unused-exports?sponsor=1" + }, + "peerDependencies": { + "typescript": ">=3.8.3" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": false + } + } + }, + "node_modules/tsc-alias": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.6.tgz", + "integrity": "sha512-vq+i6VpE83IeMsSJVcFN03ZBofADhr8/gIJXjxpbnTRfN/MFXy0+SBaKG2o7p95QqXBGkeG98HYz3IkOOveFbg==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.3", + "commander": "^9.0.0", + "globby": "^11.0.4", + "mylas": "^2.1.9", + "normalize-path": "^3.0.0", + "plimit-lit": "^1.2.6" + }, + "bin": { + "tsc-alias": "dist/bin/index.js" + } + }, + "node_modules/tsc-alias/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "optional": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "node_modules/typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/underscore": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==", + "dev": true + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/uvm": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/uvm/-/uvm-2.1.1.tgz", + "integrity": "sha512-BZ5w8adTpNNr+zczOBRpaX/hH8UPKAf7fmCnidrcsqt3bn8KT9bDIfuS7hgRU9RXgiN01su2pwysBONY6w8W5w==", + "dev": true, + "dependencies": { + "flatted": "3.2.6" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/uvm/node_modules/flatted": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "dev": true + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xml2js/node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "engines": { + "node": ">=8.0" + } + }, + "node_modules/xmlbuilder2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-3.1.0.tgz", + "integrity": "sha512-QAfrowmLOGPh99FbflhSYC6jkNKhP6MtF9A5vIwbOKR+V03MOttdEuFrMzmmramYJoTJimGeyB8PnX9ouIjM7w==", + "dev": true, + "dependencies": { + "@oozcitak/dom": "1.15.10", + "@oozcitak/infra": "1.0.8", + "@oozcitak/util": "8.3.8", + "@types/node": "*", + "js-yaml": "3.14.0" + }, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/xmlbuilder2/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/xmlbuilder2/node_modules/js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } } diff --git a/package.json b/package.json index 4821b8e..8dabcd7 100644 --- a/package.json +++ b/package.json @@ -1,41 +1,72 @@ { - "name": "pretendoverse", - "version": "1.0.0", - "description": "Miiverse API Server", - "main": "./src/server.js", - "scripts": { - "start": "node ./src/server.js", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [], - "author": "Jemma", - "license": "ISC", - "dependencies": { - "body-parser": "^1.19.0", - "colors": "^1.4.0", - "express": "^4.17.1", - "express-session": "^1.17.0", - "express-subdomain": "^1.0.5", - "fs-extra": "^9.0.0", - "moment": "^2.24.0", - "moment-timezone": "^0.5.35", - "mongoose": "^5.9.16", - "mongoose-unique-validator": "^2.0.3", - "morgan": "^1.10.0", - "node-rsa": "^1.0.8", - "node-snowflake": "0.0.1", - "pako": "^1.0.11", - "pngjs": "^5.0.0", - "sanitize": "^2.1.0", - "tga": "^1.0.3", - "xmlbuilder": "^13.0.2", - "xmlbuilder2": "0.0.4" - }, - "devDependencies": { - "multer": "^1.4.2", - "object-to-xml": "^2.0.0", - "request": "^2.88.2", - "string-sanitizer": "^1.1.1", - "xml2json": "^0.12.0" - } + "name": "miiverse-api", + "version": "2.0.0", + "description": "Miiverse API Server", + "main": "./dist/server.js", + "scripts": { + "lint": "npx eslint .", + "build": "npm run lint && npm run clean && npx tsc && npx tsc-alias", + "clean": "rimraf ./dist", + "start": "node --enable-source-maps .", + "test": "ts-node test/test.ts" + }, + "keywords": [], + "author": "Pretendo Network", + "contributors": [ + { + "name": "Jemma Poffinbarger", + "email": "contact@jemsoftware.dev", + "url": "https://jemsoftware.dev/" + }, + { + "name": "Jonathan Barrow", + "email": "jonbarrow1998@gmail.com", + "url": "https://jonbarrow.dev/" + } + ], + "license": "AGPL-3.0", + "dependencies": { + "@pretendonetwork/grpc": "^1.0.3", + "aws-sdk": "^2.1204.0", + "colors": "^1.4.0", + "crc": "^4.3.2", + "dotenv": "^16.0.3", + "express": "^4.17.1", + "express-subdomain": "^1.0.5", + "fs-extra": "^9.0.0", + "moment": "^2.24.0", + "mongoose": "^6.10.1", + "morgan": "^1.10.0", + "multer": "^1.4.5-lts.1", + "nice-grpc": "^2.0.0", + "node-rsa": "^1.0.8", + "node-snowflake": "0.0.1", + "pako": "^1.0.11", + "pngjs": "^5.0.0", + "tga": "^1.0.3", + "xmlbuilder": "^15.1.1", + "zod": "^3.21.4" + }, + "devDependencies": { + "@types/express": "^4.17.17", + "@types/fs-extra": "^11.0.1", + "@types/morgan": "^1.9.4", + "@types/multer": "^1.4.7", + "@types/newman": "^5.3.4", + "@types/node-rsa": "^1.1.1", + "@types/pako": "^2.0.0", + "@types/pngjs": "^6.0.1", + "@typescript-eslint/eslint-plugin": "^5.59.0", + "@typescript-eslint/parser": "^5.59.0", + "axios": "^1.3.6", + "eslint": "^8.38.0", + "newman": "^6.0.0", + "ora": "^5.4.1", + "postman-collection": "^4.1.7", + "table": "^6.8.1", + "ts-unused-exports": "^9.0.4", + "tsc-alias": "^1.8.5", + "typescript": "^5.0.4", + "xmlbuilder2": "^3.1.0" + } } diff --git a/postman/collections/Communities.json b/postman/collections/Communities.json new file mode 100644 index 0000000..7fd63df --- /dev/null +++ b/postman/collections/Communities.json @@ -0,0 +1,525 @@ +{ + "info": { + "_postman_id": "cb605935-6073-42c5-afa9-96d9a19c70a3", + "name": "Communities", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_uid": "19511066-cb605935-6073-42c5-afa9-96d9a19c70a3" + }, + "item": [ + { + "name": "GET /v1/communities", + "item": [ + { + "name": "Sub-Community", + "id": "0c9cf1fc-61a0-4deb-b910-e54701e39ae5", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Nintendo-ParamPack", + "value": "{{PP_MarioVsDK}}", + "type": "text" + } + ], + "url": { + "raw": "{{DOMAIN}}/v1/communities", + "host": [ + "{{DOMAIN}}" + ], + "path": [ + "v1", + "communities" + ] + } + }, + "response": [] + }, + { + "name": "Single Community", + "id": "77083b95-581f-40cf-8d83-ade183923ba0", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Nintendo-ParamPack", + "value": "{{PP_Splatoon}}", + "type": "text" + } + ], + "url": { + "raw": "{{DOMAIN}}/v1/communities", + "host": [ + "{{DOMAIN}}" + ], + "path": [ + "v1", + "communities" + ], + "query": [ + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "Invalid Title ID", + "id": "9bb6971f-f95a-4a53-960a-e9383854c2cc", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Nintendo-ParamPack", + "value": "{{PP_Bad_TID}}", + "type": "text" + } + ], + "url": { + "raw": "{{DOMAIN}}/v1/communities", + "host": [ + "{{DOMAIN}}" + ], + "path": [ + "v1", + "communities" + ], + "query": [ + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "Invalid ParamPack Format", + "id": "7e5058a3-5faa-4016-a86d-e288a1e3355f", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Nintendo-ParamPack", + "value": "{{PP_Bad Format}}", + "type": "text" + } + ], + "url": { + "raw": "{{DOMAIN}}/v1/communities", + "host": [ + "{{DOMAIN}}" + ], + "path": [ + "v1", + "communities" + ], + "query": [ + { + "key": "", + "value": "", + "type": "text", + "disabled": true + } + ] + } + }, + "response": [] + } + ], + "id": "9a31cc53-451e-4fb2-aace-ee3db9641243" + }, + { + "name": "GET /v1/communities/:id/posts", + "item": [ + { + "name": "No Params", + "id": "3ea312f0-d205-4c25-b11a-218d0b28854d", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Nintendo-ParamPack", + "value": "{{PP_Splatoon}}", + "type": "text" + } + ], + "url": { + "raw": "{{DOMAIN}}/v1/communities/0/posts", + "host": [ + "{{DOMAIN}}" + ], + "path": [ + "v1", + "communities", + "0", + "posts" + ] + } + }, + "response": [] + }, + { + "name": "Limit", + "id": "84d199be-78f5-4d65-955b-08f47b7ed1e7", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Nintendo-ParamPack", + "value": "{{PP_Splatoon}}", + "type": "text" + } + ], + "url": { + "raw": "{{DOMAIN}}/v1/communities/0/posts?limit=2", + "host": [ + "{{DOMAIN}}" + ], + "path": [ + "v1", + "communities", + "0", + "posts" + ], + "query": [ + { + "key": "limit", + "value": "2" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Key", + "id": "3754a070-9dbc-4b35-b0b8-4480d5d5aa38", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Nintendo-ParamPack", + "value": "{{PP_ACPlaza}}", + "type": "text" + } + ], + "url": { + "raw": "{{DOMAIN}}/v1/communities/0/posts?search_key=sza", + "host": [ + "{{DOMAIN}}" + ], + "path": [ + "v1", + "communities", + "0", + "posts" + ], + "query": [ + { + "key": "search_key", + "value": "sza" + } + ] + } + }, + "response": [] + }, + { + "name": "Type memo", + "id": "71362a5d-d976-402d-80d5-80e593d6ac0f", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Nintendo-ParamPack", + "value": "{{PP_ACPlaza}}", + "type": "text" + } + ], + "url": { + "raw": "{{DOMAIN}}/v1/communities/0/posts?type=memo", + "host": [ + "{{DOMAIN}}" + ], + "path": [ + "v1", + "communities", + "0", + "posts" + ], + "query": [ + { + "key": "type", + "value": "memo" + } + ] + } + }, + "response": [] + }, + { + "name": "By Followings", + "id": "70355c69-a29f-4fbc-bdb4-495b579b21f2", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Nintendo-ParamPack", + "value": "{{PP_ACPlaza}}", + "type": "text" + } + ], + "url": { + "raw": "{{DOMAIN}}/v1/communities/0/posts?by=followings", + "host": [ + "{{DOMAIN}}" + ], + "path": [ + "v1", + "communities", + "0", + "posts" + ], + "query": [ + { + "key": "by", + "value": "followings" + } + ] + } + }, + "response": [] + }, + { + "name": "By Self", + "id": "823b727d-f295-4cb3-9dbc-12c55a716ea1", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Nintendo-ParamPack", + "value": "{{PP_Splatoon}}", + "type": "text" + } + ], + "url": { + "raw": "{{DOMAIN}}/v1/communities/0/posts?by=self", + "host": [ + "{{DOMAIN}}" + ], + "path": [ + "v1", + "communities", + "0", + "posts" + ], + "query": [ + { + "key": "by", + "value": "self" + } + ] + } + }, + "response": [] + }, + { + "name": "Allow Spoiler", + "id": "875cd973-3de9-429c-b61b-ba80320ffd22", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Nintendo-ParamPack", + "value": "{{PP_Splatoon}}", + "type": "text" + } + ], + "url": { + "raw": "{{DOMAIN}}/v1/communities/0/posts?allow_spoiler=1", + "host": [ + "{{DOMAIN}}" + ], + "path": [ + "v1", + "communities", + "0", + "posts" + ], + "query": [ + { + "key": "allow_spoiler", + "value": "1" + } + ] + } + }, + "response": [] + } + ], + "id": "9078f117-f05e-459b-ac03-59be51f48ecf" + } + ], + "auth": { + "type": "apikey", + "apikey": [ + { + "key": "value", + "value": "{{ServiceToken}}", + "type": "string" + }, + { + "key": "key", + "value": "X-Nintendo-ServiceToken", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "id": "64933ef4-dc38-4d6f-a8c5-54b93decd369", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "f00757f9-3faf-40da-89ff-0f3fb356678f", + "type": "text/javascript", + "exec": [ + "const headerSchema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"result\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"has_error\": {", + " \"type\": \"string\",", + " \"maxLength\": 1", + " },", + " \"version\": {", + " \"type\": \"string\",", + " \"maxLength\": 1", + " },", + " \"expire\": {", + " \"type\": \"string\",", + " \"pattern\": \"^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]{1,3})?\"", + " },", + " \"request_name\": {", + " \"type\": \"string\"", + " }", + " },", + " \"required\": [", + " \"has_error\",", + " \"version\",", + " \"request_name\"", + " ]", + " },", + "", + " },", + " \"required\": [", + " \"result\"", + " ]", + "};", + "", + "const errorSchema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"result\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"has_error\": {", + " \"type\": \"string\",", + " \"maxLength\": 1", + " },", + " \"version\": {", + " \"type\": \"string\",", + " \"maxLength\": 1", + " },", + " \"code\": {", + " \"type\": \"string\",", + " \"maxLength\": 3", + " },", + " \"error_code\": {", + " \"type\": \"string\",", + " \"maxLength\": 4", + " },", + " \"message\": {", + " \"type\": \"string\"", + " }", + " },", + " \"required\": [", + " \"has_error\",", + " \"version\",", + " \"code\",", + " \"error_code\",", + " \"message\"", + " ]", + " },", + "", + " },", + " \"required\": [", + " \"result\"", + " ]", + "};", + "", + "pm.test(\"Valid XML Response Header\", function () {", + " var json = xml2Json(pm.response.text());", + " console.log(pm.response.code);", + " if(pm.response.code === 200)", + " pm.expect(json).to.have.jsonSchema(headerSchema);", + " else ", + " pm.expect(json).to.have.jsonSchema(errorSchema);", + " ", + "})" + ] + } + } + ] +} \ No newline at end of file diff --git a/postman/collections/People.json b/postman/collections/People.json new file mode 100644 index 0000000..8fce0e8 --- /dev/null +++ b/postman/collections/People.json @@ -0,0 +1,167 @@ +{ + "info": { + "_postman_id": "2bb4ba1f-8e09-44b9-9ad1-5f59455c0ba7", + "name": "People", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_uid": "19511066-2bb4ba1f-8e09-44b9-9ad1-5f59455c0ba7" + }, + "item": [ + { + "name": "GET /v1/people", + "item": [ + { + "name": "Friends", + "id": "688f1727-636a-4a41-ba96-a9f52c3fe2b9", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Nintendo-ParamPack", + "value": "{{PP_Splatoon}}", + "type": "text" + } + ], + "url": { + "raw": "{{DOMAIN}}/v1/people?relation=friend&distinct_pid=1", + "host": [ + "{{DOMAIN}}" + ], + "path": [ + "v1", + "people" + ], + "query": [ + { + "key": "relation", + "value": "friend" + }, + { + "key": "distinct_pid", + "value": "1" + } + ] + } + }, + "response": [] + }, + { + "name": "Following", + "id": "00b11bd6-25f1-4c16-ac6f-d8f17895ca1c", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "X-Nintendo-ParamPack", + "value": "{{PP_Splatoon}}", + "type": "text" + } + ], + "url": { + "raw": "{{DOMAIN}}/v1/people?relation=following&distinct_pid=1", + "host": [ + "{{DOMAIN}}" + ], + "path": [ + "v1", + "people" + ], + "query": [ + { + "key": "relation", + "value": "following" + }, + { + "key": "distinct_pid", + "value": "1" + } + ] + } + }, + "response": [] + } + ], + "id": "826dbc90-90a0-483c-a94f-5d93f48a1804" + } + ], + "auth": { + "type": "apikey", + "apikey": [ + { + "key": "value", + "value": "{{ServiceToken}}", + "type": "string" + }, + { + "key": "key", + "value": "X-Nintendo-ServiceToken", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "id": "86097a74-4b68-4b97-b176-45bcbedd2abf", + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "id": "540f44d8-e877-4739-ad86-0e471f183a27", + "type": "text/javascript", + "exec": [ + "const headerSchema = {", + " \"type\": \"object\",", + " \"properties\": {", + " \"result\": {", + " \"type\": \"object\",", + " \"properties\": {", + " \"has_error\": {", + " \"type\": \"string\",", + " \"maxLength\": 1", + " },", + " \"version\": {", + " \"type\": \"string\",", + " \"maxLength\": 1", + " },", + " \"expire\": {", + " \"type\": \"string\",", + " \"pattern\": \"^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]{1,3})?\"", + " },", + " \"request_name\": {", + " \"type\": \"string\"", + " }", + " },", + " \"required\": [", + " \"has_error\",", + " \"version\",", + " \"request_name\"", + " ]", + " },", + "", + " },", + " \"required\": [", + " \"result\"", + " ]", + "};", + "", + "pm.test(\"Valid XML Response Header\", function () {", + " var json = xml2Json(pm.response.text());", + " pm.expect(json).to.have.jsonSchema(headerSchema);", + "})" + ] + } + } + ] +} \ No newline at end of file diff --git a/src/cache.ts b/src/cache.ts new file mode 100644 index 0000000..e8f9743 --- /dev/null +++ b/src/cache.ts @@ -0,0 +1,27 @@ +export default class Cache { + private data?: T; + private expireAt: number; + private cacheTime: number; + + constructor(cacheTime: number) { + this.expireAt = Date.now() + cacheTime; + this.cacheTime = cacheTime; + } + + valid(): boolean { + if (!this.data || Date.now() >= this.expireAt) { + return false; + } + + return true; + } + + update(data: T): void { + this.expireAt = Date.now() + this.cacheTime; + this.data = data; + } + + get(): T | undefined { + return this.data; + } +} \ No newline at end of file diff --git a/src/config-manager.ts b/src/config-manager.ts new file mode 100644 index 0000000..ff0c641 --- /dev/null +++ b/src/config-manager.ts @@ -0,0 +1,113 @@ +import fs from 'fs-extra'; +import mongoose from 'mongoose'; +import dotenv from 'dotenv'; +import { LOG_INFO, LOG_WARN, LOG_ERROR } from '@/logger'; +import { Config } from '@/types/common/config'; + +dotenv.config(); + +LOG_INFO('Loading config'); + +let mongooseConnectOptionsMain: mongoose.ConnectOptions = {}; + +if (process.env.PN_MIIVERSE_API_CONFIG_MONGOOSE_CONNECT_OPTIONS_PATH) { + mongooseConnectOptionsMain = fs.readJSONSync(process.env.PN_MIIVERSE_API_CONFIG_MONGOOSE_CONNECT_OPTIONS_PATH); +} else { + LOG_WARN('No Mongoose connection options found for main connection. To add connection options, set PN_MIIVERSE_API_CONFIG_MONGOOSE_CONNECT_OPTIONS_PATH to the path of your options JSON file'); +} + +export const config: Config = { + http: { + port: Number(process.env.PN_MIIVERSE_API_CONFIG_HTTP_PORT || '') + }, + account_server_address: process.env.PN_MIIVERSE_API_CONFIG_ACCOUNT_SERVER_ADDRESS || '', + mongoose: { + connection_string: process.env.PN_MIIVERSE_API_CONFIG_MONGO_CONNECTION_STRING || '', + options: mongooseConnectOptionsMain + }, + s3: { + endpoint: process.env.PN_MIIVERSE_API_CONFIG_S3_ENDPOINT || '', + key: process.env.PN_MIIVERSE_API_CONFIG_S3_ACCESS_KEY || '', + secret: process.env.PN_MIIVERSE_API_CONFIG_S3_ACCESS_SECRET || '' + }, + grpc: { + friends: { + ip: process.env.PN_MIIVERSE_API_CONFIG_GRPC_FRIENDS_IP || '', + port: Number(process.env.PN_MIIVERSE_API_CONFIG_GRPC_FRIENDS_PORT || ''), + api_key: process.env.PN_MIIVERSE_API_CONFIG_GRPC_FRIENDS_API_KEY || '' + }, + account: { + ip: process.env.PN_MIIVERSE_API_CONFIG_GRPC_ACCOUNT_IP || '', + port: Number(process.env.PN_MIIVERSE_API_CONFIG_GRPC_ACCOUNT_PORT || ''), + api_key: process.env.PN_MIIVERSE_API_CONFIG_GRPC_ACCOUNT_API_KEY || '' + } + }, + aes_key: process.env.PN_MIIVERSE_API_CONFIG_AES_KEY || '' +}; + +LOG_INFO('Config loaded, checking integrity'); + +if (!config.http.port) { + LOG_ERROR('Failed to find HTTP port. Set the PN_MIIVERSE_API_CONFIG_HTTP_PORT environment variable'); + process.exit(0); +} + +if (!config.account_server_address) { + LOG_ERROR('Failed to find account server address. Set the PN_MIIVERSE_API_CONFIG_ACCOUNT_SERVER_ADDRESS environment variable'); + process.exit(0); +} + +if (!config.mongoose.connection_string) { + LOG_ERROR('Failed to find MongoDB connection string. Set the PN_MIIVERSE_API_CONFIG_MONGO_CONNECTION_STRING environment variable'); + process.exit(0); +} + +if (!config.s3.endpoint) { + LOG_ERROR('Failed to find s3 endpoint. Set the PN_MIIVERSE_API_CONFIG_S3_ENDPOINT environment variable'); + process.exit(0); +} + +if (!config.s3.key) { + LOG_ERROR('Failed to find s3 key. Set the PN_MIIVERSE_API_CONFIG_S3_ACCESS_KEY environment variable'); + process.exit(0); +} + +if (!config.s3.secret) { + LOG_ERROR('Failed to find s3 secret. Set the PN_MIIVERSE_API_CONFIG_S3_ACCESS_SECRET environment variable'); + process.exit(0); +} + +if (!config.grpc.friends.ip) { + LOG_ERROR('Failed to find NEX Friends gRPC ip. Set the PN_MIIVERSE_API_CONFIG_GRPC_FRIENDS_IP environment variable'); + process.exit(0); +} + +if (!config.grpc.friends.port) { + LOG_ERROR('Failed to find NEX Friends gRPC port. Set the PN_MIIVERSE_API_CONFIG_GRPC_FRIENDS_PORT environment variable'); + process.exit(0); +} + +if (!config.grpc.friends.api_key) { + LOG_ERROR('Failed to find NEX Friends gRPC API key. Set the PN_MIIVERSE_API_CONFIG_GRPC_FRIENDS_API_KEY environment variable'); + process.exit(0); +} + +if (!config.grpc.account.ip) { + LOG_ERROR('Failed to find account server gRPC ip. Set the PN_MIIVERSE_API_CONFIG_GRPC_ACCOUNT_IP environment variable'); + process.exit(0); +} + +if (!config.grpc.account.port) { + LOG_ERROR('Failed to find account server gRPC port. Set the PN_MIIVERSE_API_CONFIG_GRPC_ACCOUNT_PORT environment variable'); + process.exit(0); +} + +if (!config.grpc.account.api_key) { + LOG_ERROR('Failed to find account server gRPC API key. Set the PN_MIIVERSE_API_CONFIG_GRPC_ACCOUNT_API_KEY environment variable'); + process.exit(0); +} + +if (!config.aes_key) { + LOG_ERROR('Token AES key is not set. Set the PN_MIIVERSE_API_CONFIG_AES_KEY environment variable to your AES-256-CBC key'); + process.exit(0); +} \ No newline at end of file diff --git a/src/database.js b/src/database.js deleted file mode 100644 index 893e77e..0000000 --- a/src/database.js +++ /dev/null @@ -1,371 +0,0 @@ -const mongoose = require('mongoose'); -const { mongoose: mongooseConfig } = require('../config.json'); -const { ENDPOINT } = require('./models/endpoint'); -const { COMMUNITY } = require('./models/communities'); -const { POST } = require('./models/post'); -const { USER } = require('./models/user'); -const { CONVERSATION } = require('./models/conversation'); -const { uri, database, options } = mongooseConfig; -const logger = require('./logger'); - -let connection; - -async function connect() { - await mongoose.connect(`${uri}/${database}`, options); - connection = mongoose.connection; - connection.on('connected', function () { - logger.info(`MongoDB connected ${this.name}`); - }); - connection.on('error', console.error.bind(console, 'connection error:')); - connection.on('close', () => { - connection.removeAllListeners(); - }); -} - -function verifyConnected() { - if (!connection) { - connect(); - } -} - -async function getCommunities(numberOfCommunities) { - verifyConnected(); - if(numberOfCommunities === -1) - return COMMUNITY.find({ parent: null }); - else - return COMMUNITY.find({ parent: null }).limit(numberOfCommunities); -} - -async function getMostPopularCommunities(numberOfCommunities) { - verifyConnected(); - return COMMUNITY.find({ parent: null }).sort({followers: -1}).limit(numberOfCommunities); -} - -async function getNewCommunities(numberOfCommunities) { - verifyConnected(); - return COMMUNITY.find({ parent: null }).sort([['created_at', -1]]).limit(numberOfCommunities); -} - -async function getSubCommunities(communityID) { - verifyConnected(); - return COMMUNITY.find({ - parent: communityID - }); -} - -async function getCommunityByTitleID(title_id) { - verifyConnected(); - return COMMUNITY.findOne({ - title_id: title_id - }); -} - -async function getCommunityByID(community_id) { - verifyConnected(); - return COMMUNITY.findOne({ - community_id: community_id - }); -} - -async function getTotalPostsByCommunity(community) { - verifyConnected(); - return POST.find({ - title_id: community.title_id, - parent: null - }).countDocuments(); -} - -async function getPostByID(postID) { - verifyConnected(); - - return POST.findOne({ - id: postID - }); -} - -async function getPostsByUserID(userID) { - verifyConnected(); - return POST.find({ - pid: userID, - parent: null - }); -} - -async function getPostReplies(postID, number) { - verifyConnected(); - return POST.find({ - parent: postID - }).limit(number); -} - -async function getUserPostRepliesAfterTimestamp(post, numberOfPosts) { - verifyConnected(); - return POST.find({ - parent: post.pid, - created_at: { $lt: post.created_at } - }).limit(numberOfPosts); -} - -async function getNumberUserPostsByID(userID, number) { - verifyConnected(); - return POST.find({ - pid: userID, - parent: null - }).sort({ created_at: -1}).limit(number); -} - -async function getTotalPostsByUserID(userID) { - verifyConnected(); - return POST.find({ - pid: userID, - parent: null - }).countDocuments(); -} - -async function getHotPostsByCommunity(community, numberOfPosts) { - verifyConnected(); - return POST.find({ - title_id: community.title_id, - parent: null - }).sort({empathy_count: -1}).limit(numberOfPosts); -} - -async function getNumberNewCommunityPostsByID(community, number) { - verifyConnected(); - return POST.find({ - title_id: community.title_id, - parent: null - }).sort({ created_at: -1}).limit(number); -} - -async function getNumberPopularCommunityPostsByID(community, limit, offset) { - verifyConnected(); - return POST.find({ - title_id: community.title_id, - parent: null - }).sort({ empathy_count: -1}).skip(offset).limit(limit); -} - -async function getNumberVerifiedCommunityPostsByID(community, limit, offset) { - verifyConnected(); - return POST.find({ - title_id: community.title_id, - verified: true, - parent: null - }).sort({ created_at: -1}).skip(offset).limit(limit); -} - -async function getPostsByCommunity(community, numberOfPosts) { - verifyConnected(); - return POST.find({ - title_id: community.title_id, - parent: null - }).limit(numberOfPosts); -} - -async function getPostsByCommunityKey(community, numberOfPosts, search_key) { - verifyConnected(); - return POST.find({ - title_id: community.title_id, - search_key: search_key, - parent: null - }).limit(numberOfPosts); -} - -async function getNewPostsByCommunity(community, limit, offset) { - verifyConnected(); - return POST.find({ - community_id: community.community_id, - parent: null - }).sort({ created_at: -1 }).skip(offset).limit(limit); -} - -async function getUserPostsAfterTimestamp(post, numberOfPosts) { - verifyConnected(); - return POST.find({ - pid: post.pid, - created_at: { $lt: post.created_at }, - parent: null - }).limit(numberOfPosts); -} - -async function getUserPostsOffset(pid, limit, offset) { - verifyConnected(); - return POST.find({ - pid: pid, - parent: null - }).sort({ created_at: -1}).skip(offset).limit(limit); -} - -async function getCommunityPostsAfterTimestamp(post, numberOfPosts) { - verifyConnected(); - return POST.find({ - title_id: post.title_id, - created_at: { $lt: post.created_at }, - parent: null - }).limit(numberOfPosts); -} - -async function pushNewNotificationByPID(PID, content, link) { - verifyConnected(); - return USER.update( - { pid: PID }, { $push: { notification_list: { content: content, link: link, read: false, created_at: Date() }}}); -} - -async function pushNewNotificationToAll(content, link) { - verifyConnected(); - return USER.updateMany( - {}, { $push: { notification_list: { content: content, link: link, read: false, created_at: Date() }}}); -} - -async function getDiscoveryHosts() { - verifyConnected(); - return ENDPOINT.findOne({ - version: 1 - }); -} - -async function getUsers(numberOfUsers) { - verifyConnected(); - if(numberOfUsers === -1) - return USER.find({}); - else - return USER.find({}).limit(numberOfUsers); -} - -async function getFollowingUsers(user) { - verifyConnected(); - return USER.find({ - pid: user.following_users - }); -} -async function getFollowedUsers(user) { - verifyConnected(); - return USER.find({ - pid: user.followed_users - }); -} - -async function getUserByPID(PID) { - verifyConnected(); - - return USER.findOne({ - pid: PID - }); -} - -async function getUserByUsername(user_id) { - verifyConnected(); - - return USER.findOne({ - pnid: new RegExp(`^${user_id}$`, 'i') - }); -} - -async function getServerConfig() { - verifyConnected(); - return ENDPOINT.findOne(); -} - -async function getNewsFeed(user, numberOfPosts) { - verifyConnected(); - return POST.find({ - $or: [ - {pid: user.followed_users}, - {pid: user.pid} - ], - parent: null - }).limit(numberOfPosts).sort({ created_at: -1}); -} - -async function getNewsFeedAfterTimestamp(user, numberOfPosts, post) { - verifyConnected(); - return POST.find({ - $or: [ - {pid: user.followed_users}, - {pid: user.pid} - ], - created_at: { $lt: post.created_at }, - parent: null - }).limit(numberOfPosts).sort({ created_at: -1}); -} - -async function getNewsFeedOffset(user, limit, offset) { - verifyConnected(); - return POST.find({ - $or: [ - {pid: user.followed_users}, - {pid: user.pid} - ], - parent: null - }).skip(offset).limit(limit).sort({ created_at: -1}); -} - -async function getConversations(pid) { - verifyConnected(); - return CONVERSATION.find({ - pids: pid - }); -} - -async function getConversation(pid, pid2) { - verifyConnected(); - return CONVERSATION.find({ - $and: [ - {pids: pid}, - {pids: pid2} - ], - }); -} - -async function getLatestMessage(pid, pid2) { - verifyConnected(); - return POST.findOne({ - $or: [ - {pid: pid, message_to_pid: pid2}, - {pid: pid2, message_to_pid: pid} - ] - }) -} - -module.exports = { - connect, - getCommunities, - getMostPopularCommunities, - getNewCommunities, - getSubCommunities, - getCommunityByTitleID, - getCommunityByID, - getTotalPostsByCommunity, - getDiscoveryHosts, - getPostsByCommunity, - getHotPostsByCommunity, - getNumberNewCommunityPostsByID, - getNumberPopularCommunityPostsByID, - getNumberVerifiedCommunityPostsByID, - getNewPostsByCommunity, - getPostsByCommunityKey, - getPostsByUserID, - getPostReplies, - getUserPostRepliesAfterTimestamp, - getNumberUserPostsByID, - getTotalPostsByUserID, - getPostByID, - getUsers, - getUserByPID, - getUserByUsername, - getUserPostsAfterTimestamp, - getUserPostsOffset, - getCommunityPostsAfterTimestamp, - getServerConfig, - pushNewNotificationByPID, - pushNewNotificationToAll, - getNewsFeed, - getNewsFeedAfterTimestamp, - getNewsFeedOffset, - getFollowingUsers, - getFollowedUsers, - getConversations, - getConversation, - getLatestMessage, -}; diff --git a/src/database.ts b/src/database.ts new file mode 100644 index 0000000..6f2a45d --- /dev/null +++ b/src/database.ts @@ -0,0 +1,179 @@ +import mongoose from 'mongoose'; +import { LOG_INFO } from '@/logger'; +import { Community } from '@/models/community'; +import { Content } from '@/models/content'; +import { Conversation } from '@/models/conversation'; +import { Endpoint } from '@/models/endpoint'; +import { Post } from '@/models/post'; +import { Settings } from '@/models/settings'; +import { config } from '@/config-manager'; +import { HydratedCommunityDocument } from '@/types/mongoose/community'; +import { HydratedPostDocument, IPost } from '@/types/mongoose/post'; +import { HydratedEndpointDocument } from '@/types/mongoose/endpoint'; +import { HydratedSettingsDocument } from '@/types/mongoose/settings'; +import { HydratedContentDocument } from '@/types/mongoose/content'; +import { HydratedConversationDocument } from '@/types/mongoose/conversation'; + +const { mongoose: mongooseConfig } = config; + +let connection: mongoose.Connection; + +export async function connect(): Promise { + await mongoose.connect(mongooseConfig.connection_string, mongooseConfig.options); + + connection = mongoose.connection; + connection.on('connected', () => { + LOG_INFO('MongoDB connected'); + }); + connection.on('error', console.error.bind(console, 'connection error:')); + connection.on('close', () => { + connection.removeAllListeners(); + }); +} + +function verifyConnected(): void { + if (!connection) { + connect(); + } +} + +export async function getMostPopularCommunities(limit: number): Promise { + verifyConnected(); + + return Community.find({ parent: null, type: 0 }).sort({ followers: -1 }).limit(limit); +} + +export async function getNewCommunities(limit: number): Promise { + verifyConnected(); + + return Community.find({ parent: null, type: 0 }).sort([['created_at', -1]]).limit(limit); +} + +export async function getSubCommunities(parentCommunityID: string): Promise { + verifyConnected(); + + return Community.find({ + parent: parentCommunityID + }); +} + +export async function getCommunityByTitleID(titleID: string): Promise { + verifyConnected(); + + return Community.findOne({ + title_id: titleID + }); +} + +export async function getCommunityByTitleIDs(titleIDs: string[]): Promise { + verifyConnected(); + + return Community.findOne({ + title_id: { $in: titleIDs } + }); +} + +export async function getCommunityByID(communityID: string): Promise { + verifyConnected(); + + return Community.findOne({ + community_id: communityID + }); +} + +export async function getPostByID(postID: string): Promise { + verifyConnected(); + + return Post.findOne({ + id: postID + }); +} + +export async function getPostReplies(postID: string, limit: number): Promise { + verifyConnected(); + + return Post.find({ + parent: postID, + removed: false, + app_data: { $ne: null } + }).limit(limit); +} + +export async function getDuplicatePosts(pid: number, post: IPost): Promise { + verifyConnected(); + + return Post.findOne({ + pid: pid, + body: post.body, + painting: post.painting, + screenshot: post.screenshot, + parent: null, + removed: false + }); +} + +export async function getPostsBytitleID(titleID: string[], limit: number): Promise { + verifyConnected(); + + return Post.find({ + title_id: titleID, + parent: null, + removed: false + }).sort({ created_at: -1 }).limit(limit); +} + +export async function getEndpoints(): Promise { + verifyConnected(); + + return Endpoint.find({}); +} + +export async function getEndpoint(accessLevel: string): Promise { + verifyConnected(); + + return Endpoint.findOne({ + server_access_level: accessLevel + }); +} + +export async function getUserSettings(pid: number): Promise { + verifyConnected(); + + return Settings.findOne({ pid: pid }); +} + +export async function getUserContent(pid: number): Promise { + verifyConnected(); + + return Content.findOne({ pid: pid }); +} + +export async function getFollowedUsers(content: HydratedContentDocument): Promise { + verifyConnected(); + + return Settings.find({ + pid: content.followed_users + }); +} + +export async function getConversationByUsers(pids: number[]): Promise { + verifyConnected(); + + return Conversation.findOne({ + $and: [ + { 'users.pid': pids[0] }, + { 'users.pid': pids[1] } + ] + }); +} + +export async function getFriendMessages(pid: string, search_key: string[], limit: number): Promise { + verifyConnected(); + + return Post.find({ + message_to_pid: pid, + search_key: search_key, + parent: null, + removed: false + }).sort({ created_at: 1 }).limit(limit); +} \ No newline at end of file diff --git a/src/logger.js b/src/logger.ts similarity index 73% rename from src/logger.js rename to src/logger.ts index eda058e..21bb483 100644 --- a/src/logger.js +++ b/src/logger.ts @@ -1,7 +1,9 @@ -const fs = require('fs-extra'); -require('colors'); +import fs from 'fs-extra'; +import colors from 'colors'; -const root = __dirname; +colors.enable(); + +const root = process.env.PN_MIIVERSE_API_LOGGER_PATH ? process.env.PN_MIIVERSE_API_LOGGER_PATH : `${__dirname}/..`; fs.ensureDirSync(`${root}/logs`); const streams = { @@ -10,9 +12,9 @@ const streams = { error: fs.createWriteStream(`${root}/logs/error.log`), warn: fs.createWriteStream(`${root}/logs/warn.log`), info: fs.createWriteStream(`${root}/logs/info.log`) -}; +} as const; -function success(input) { +export function LOG_SUCCESS(input: string): void { const time = new Date(); input = `[${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}] [SUCCESS]: ${input}`; streams.success.write(`${input}\n`); @@ -20,7 +22,7 @@ function success(input) { console.log(`${input}`.green.bold); } -function error(input) { +export function LOG_ERROR(input: string): void { const time = new Date(); input = `[${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}] [ERROR]: ${input}`; streams.error.write(`${input}\n`); @@ -28,7 +30,7 @@ function error(input) { console.log(`${input}`.red.bold); } -function warn(input) { +export function LOG_WARN(input: string): void { const time = new Date(); input = `[${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}] [WARN]: ${input}`; streams.warn.write(`${input}\n`); @@ -36,17 +38,10 @@ function warn(input) { console.log(`${input}`.yellow.bold); } -function info(input) { +export function LOG_INFO(input: string): void { const time = new Date(); input = `[${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}] [INFO]: ${input}`; streams.info.write(`${input}\n`); console.log(`${input}`.cyan.bold); -} - -module.exports = { - success, - error, - warn, - info -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/middleware/auth.ts b/src/middleware/auth.ts new file mode 100644 index 0000000..e1bc9af --- /dev/null +++ b/src/middleware/auth.ts @@ -0,0 +1,175 @@ +import express from 'express'; +import xmlbuilder from 'xmlbuilder'; +import { z } from 'zod'; +import { GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc'; +import { getEndpoint } from '@/database'; +import { getUserAccountData, getValueFromHeaders, decodeParamPack, getPIDFromServiceToken } from '@/util'; +import { HydratedEndpointDocument } from '@/types/mongoose/endpoint'; + +const ParamPackSchema = z.object({ + title_id: z.string(), + access_key: z.string(), + platform_id: z.string(), + region_id: z.string(), + language_id: z.string(), + country_id: z.string(), + area_id: z.string(), + network_restriction: z.string(), + friend_restriction: z.string(), + rating_restriction: z.string(), + rating_organization: z.string(), + transferable_id: z.string(), + tz_name: z.string(), + utc_offset: z.string(), + remaster_version: z.string().optional() +}); + +async function auth(request: express.Request, response: express.Response, next: express.NextFunction): Promise { + if (request.path.includes('/v1/status')) { + return next(); + } + + // * Just don't care about the token here + if (request.path === '/v1/topics') { + return next(); + } + + let encryptedToken = getValueFromHeaders(request.headers, 'x-nintendo-servicetoken'); + if (!encryptedToken) { + encryptedToken = getValueFromHeaders(request.headers, 'olive service token'); + } + + if (!encryptedToken) { + return badAuth(response, 15, 'NO_TOKEN'); + } + + const pid: number = getPIDFromServiceToken(encryptedToken); + if (pid === 0) { + return badAuth(response, 16, 'BAD_TOKEN'); + } + + const paramPack = getValueFromHeaders(request.headers, 'x-nintendo-parampack'); + if (!paramPack) { + return badAuth(response, 17, 'NO_PARAM'); + } + + const paramPackData = decodeParamPack(paramPack); + const paramPackCheck = ParamPackSchema.safeParse(paramPackData); + if (!paramPackCheck.success) { + console.log(paramPackCheck.error); + return badAuth(response, 18, 'BAD_PARAM'); + } + + let user: GetUserDataResponse; + + try { + user = await getUserAccountData(pid); + } catch (error) { + // TODO - Log this error + console.log(error); + return badAuth(response, 18, 'BAD_PARAM'); + } + + let discovery: HydratedEndpointDocument | null; + + if (user) { + discovery = await getEndpoint(user.serverAccessLevel); + } else { + discovery = await getEndpoint('prod'); + } + + if (!discovery) { + return badAuth(response, 19, 'NO_DISCOVERY'); + } + + if (discovery.status !== 0) { + return serverError(response, discovery); + } + + // TODO - This is temp, testing something. Will be removed in the future + if (request.path !== '/v1/endpoint') { + if (user.serverAccessLevel !== 'test' && user.serverAccessLevel !== 'dev') { + return badAuth(response, 16, 'BAD_TOKEN'); + } + } + + // * This is a false positive from ESLint. + // * Since this middleware is only ever called + // * per every request instance + // eslint-disable-next-line require-atomic-updates + request.pid = pid; + // eslint-disable-next-line require-atomic-updates + request.paramPack = paramPackData; + + return next(); +} + +function badAuth(response: express.Response, errorCode: number, message: string): void { + response.type('application/xml'); + response.status(400); + + response.send(xmlbuilder.create({ + result: { + has_error: 1, + version: 1, + code: 400, + error_code: errorCode, + message: message + } + }).end({ pretty: true })); +} + +function serverError(response: express.Response, discovery: HydratedEndpointDocument): void { + let message = ''; + let error = 0; + + switch (discovery.status) { + case 1: + message = 'SYSTEM_UPDATE_REQUIRED'; + error = 1; + break; + case 2: + message = 'SETUP_NOT_COMPLETE'; + error = 2; + break; + case 3: + message = 'SERVICE_MAINTENANCE'; + error = 3; + break; + case 4: + message = 'SERVICE_CLOSED'; + error = 4; + break; + case 5: + message = 'PARENTAL_CONTROLS_ENABLED'; + error = 5; + break; + case 6: + message = 'POSTING_LIMITED_PARENTAL_CONTROLS'; + error = 6; + break; + case 7: + message = 'NNID_BANNED'; + error = 7; + break; + default: + message = 'SERVER_ERROR'; + error = 15; + break; + } + + response.type('application/xml'); + response.status(400); + + response.send(xmlbuilder.create({ + result: { + has_error: 1, + version: 1, + code: 400, + error_code: error, + message: message + } + }).end({ pretty: true })); +} + +export default auth; diff --git a/src/middleware/client-header.js b/src/middleware/client-header.js deleted file mode 100644 index e722968..0000000 --- a/src/middleware/client-header.js +++ /dev/null @@ -1,38 +0,0 @@ -const xmlbuilder = require('xmlbuilder'); - -const VALID_CLIENT_ID_SECRET_PAIRS = { - // 'Key' is the client ID, 'Value' is the client secret - 'a2efa818a34fa16b8afbc8a74eba3eda': 'c91cdb5658bd4954ade78533a339cf9a', // Possibly WiiU exclusive? - 'daf6227853bcbdce3d75baee8332b': '3eff548eac636e2bf45bb7b375e7b6b0', // Possibly 3DS exclusive? - 'ea25c66c26b403376b4c5ed94ab9cdea': 'd137be62cb6a2b831cad8c013b92fb55', // Possibly 3DS exclusive? -}; - - -function nintendoClientHeaderCheck(request, response, next) { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); - - const {headers} = request; - - if ( - !headers['x-nintendo-client-id'] || - !headers['x-nintendo-client-secret'] || - !VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || - headers['x-nintendo-client-secret'] !== VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] - ) { - return response.send(xmlbuilder.create({ - errors: { - error: { - cause: 'client_id', - code: '0004', - message: 'API application invalid or incorrect application credentials' - } - } - }).end()); - } - - return next(); -} - -module.exports = nintendoClientHeaderCheck; \ No newline at end of file diff --git a/src/middleware/client-header.ts b/src/middleware/client-header.ts new file mode 100644 index 0000000..7b40938 --- /dev/null +++ b/src/middleware/client-header.ts @@ -0,0 +1,44 @@ +import express from 'express'; +import xmlbuilder from 'xmlbuilder'; +import { getValueFromHeaders } from '@/util'; + +const VALID_CLIENT_ID_SECRET_PAIRS: { [key: string]: string } = { + // * 'Key' is the client ID, 'Value' is the client secret + 'a2efa818a34fa16b8afbc8a74eba3eda': 'c91cdb5658bd4954ade78533a339cf9a', // * Possibly WiiU exclusive? + 'daf6227853bcbdce3d75baee8332b': '3eff548eac636e2bf45bb7b375e7b6b0', // * Possibly 3DS exclusive? + 'ea25c66c26b403376b4c5ed94ab9cdea': 'd137be62cb6a2b831cad8c013b92fb55', // * Possibly 3DS exclusive? +}; + + +function nintendoClientHeaderCheck(request: express.Request, response: express.Response, next: express.NextFunction): void { + response.type('text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime().toString()); + + const clientID = getValueFromHeaders(request.headers, 'x-nintendo-client-id'); + const clientSecret = getValueFromHeaders(request.headers, 'x-nintendo-client-secret'); + + if ( + !clientID || + !clientSecret || + !VALID_CLIENT_ID_SECRET_PAIRS[clientID] || + clientSecret !== VALID_CLIENT_ID_SECRET_PAIRS[clientID] + ) { + response.type('application/xml'); + response.send(xmlbuilder.create({ + errors: { + error: { + cause: 'client_id', + code: '0004', + message: 'API application invalid or incorrect application credentials' + } + } + }).end()); + + return; + } + + return next(); +} + +export default nintendoClientHeaderCheck; \ No newline at end of file diff --git a/src/middleware/pnid.js b/src/middleware/pnid.js deleted file mode 100644 index 5d47cde..0000000 --- a/src/middleware/pnid.js +++ /dev/null @@ -1,50 +0,0 @@ -const xmlbuilder = require('xmlbuilder'); -const database = require('../database'); - -async function PNIDMiddleware(request, response, next) { - const { headers } = request; - - if (!headers.authorization || !(headers.authorization.startsWith('Bearer') || headers.authorization.startsWith('Basic'))) { - return next(); - } - - const [type, token] = headers.authorization.split(' '); - let user; - - if (type === 'Basic') { - user = await database.getUserBasic(token); - } else { - user = await database.getUserBearer(token); - } - - if (!user) { - response.status(401); - - if (type === 'Bearer') { - return response.send(xmlbuilder.create({ - errors: { - error: { - cause: 'access_token', - code: '0005', - message: 'Invalid access token' - } - } - }).end()); - } - - return response.send(xmlbuilder.create({ - errors: { - error: { - code: '1105', - message: 'Email address, username, or password, is not valid' - } - } - }).end()); - } - - request.pnid = user; - - return next(); -} - -module.exports = PNIDMiddleware; \ No newline at end of file diff --git a/src/middleware/session.js b/src/middleware/session.js deleted file mode 100644 index e8b663f..0000000 --- a/src/middleware/session.js +++ /dev/null @@ -1,23 +0,0 @@ -// super basic and there's probably a much better way to do this - -// this will only be used during the registration process, to track the progress of the user -// express-session uses cookies which the WiiU does not support during the registration process - -// temp, in-memory session storage -const sessionStore = {}; - -function sessionMiddlware(request, response, next) { - const ip = request.headers['x-forwarded-for'] || request.connection.remoteAddress; - - if (!sessionStore[ip]) { - sessionStore[ip] = {}; - } - - const session = sessionStore[ip]; - - request.session = session; - - return next(); -} - -module.exports = sessionMiddlware; \ No newline at end of file diff --git a/src/middleware/xml-parser.js b/src/middleware/xml-parser.js deleted file mode 100644 index 12fb614..0000000 --- a/src/middleware/xml-parser.js +++ /dev/null @@ -1,35 +0,0 @@ -const { document: xmlParser } = require('xmlbuilder2'); - -function XMLMiddleware(request, response, next) { - if (request.method == 'POST' || request.method == 'PUT') { - const headers = request.headers; - let body = ''; - - if ( - !headers['content-type'] || - !headers['content-type'].toLowerCase().includes('xml') - ) { - return next(); - } - - request.setEncoding('utf-8'); - request.on('data', (chunk) => { - body += chunk; - }); - - request.on('end', () => { - try { - request.body = xmlParser(body); - request.body = request.body.toObject(); - } catch (error) { - return next(); - } - - next(); - }); - } else { - next(); - } -} - -module.exports = XMLMiddleware; \ No newline at end of file diff --git a/src/models/communities.js b/src/models/communities.js deleted file mode 100644 index 06595a9..0000000 --- a/src/models/communities.js +++ /dev/null @@ -1,101 +0,0 @@ -const { Schema, model } = require('mongoose'); - -const CommunitySchema = new Schema({ - platform_id: Number, - name: String, - description: String, - open: { - type: Boolean, - default: true - }, - /** - * 0: Main Community - * 1: Sub-Community - * 2: Announcement Community - */ - type: { - type: Number, - default: 0 - }, - parent: { - type: Number, - default: null - }, - admins: { - type: [String], - default: undefined - }, - created_at: { - type: Date, - default: new Date(), - }, - empathy_count: { - type: Number, - default: 0 - }, - followers: { - type: Number, - default: 0 - }, - id: { - type: Number, - default: 0 - }, - has_shop_page: { - type: Number, - default: 0 - }, - icon: String, - title_ids: { - type: [String], - default: undefined - }, - title_id: { - type: [String], - default: undefined - }, - community_id: String, - is_recommended: { - type: Number, - default: 0 - }, - browser_icon: String, - browser_thumbnail: String, - CTR_browser_header: String, - WiiU_browser_header: String -}); - -CommunitySchema.methods.upEmpathy = async function() { - const empathy = this.get('empathy_count'); - this.set('empathy_count', empathy + 1); - - await this.save(); -}; - -CommunitySchema.methods.downEmpathy = async function() { - const empathy = this.get('empathy_count'); - this.set('empathy_count', empathy - 1); - - await this.save(); -}; - -CommunitySchema.methods.upFollower = async function() { - const followers = this.get('followers'); - this.set('followers', followers + 1); - - await this.save(); -}; - -CommunitySchema.methods.downFollower = async function() { - const followers = this.get('followers'); - this.set('followers', followers - 1); - - await this.save(); -}; - -const COMMUNITY = model('COMMUNITY', CommunitySchema); - -module.exports = { - CommunitySchema, - COMMUNITY -}; diff --git a/src/models/community.ts b/src/models/community.ts new file mode 100644 index 0000000..7ff1a50 --- /dev/null +++ b/src/models/community.ts @@ -0,0 +1,103 @@ +import { Schema, model } from 'mongoose'; +import { CommunityData } from '@/types/miiverse/community'; +import { ICommunity, ICommunityMethods, CommunityModel, HydratedCommunityDocument } from '@/types/mongoose/community'; + +const CommunitySchema = new Schema({ + platform_id: Number, + name: String, + description: String, + open: { + type: Boolean, + default: true + }, + allows_comments: { + type: Boolean, + default: true + }, + /** + * 0: Main Community + * 1: Sub-Community + * 2: Announcement Community + * 3: Private Community + */ + type: { + type: Number, + default: 0 + }, + parent: { + type: String, + default: null + }, + admins: { + type: [Number], + default: undefined + }, + owner: Number, + created_at: { + type: Date, + default: new Date(), + }, + empathy_count: { + type: Number, + default: 0 + }, + followers: { + type: Number, + default: 0 + }, + has_shop_page: { + type: Number, + default: 0 + }, + icon: String, + title_ids: { + type: [String], + default: undefined + }, + title_id: { + type: [String], + default: undefined + }, + community_id: String, + olive_community_id: String, + is_recommended: { + type: Number, + default: 0 + }, + app_data: String, + user_favorites: { + type: [Number], + default: [] + } +}); + +CommunitySchema.method('addUserFavorite', async function addUserFavorite(pid: number): Promise { + if (!this.user_favorites.includes(pid)) { + this.user_favorites.push(pid); + } + + await this.save(); +}); + +CommunitySchema.method('delUserFavorite', async function delUserFavorite(pid: number): Promise { + if (this.user_favorites.includes(pid)) { + this.user_favorites.splice(this.user_favorites.indexOf(pid), 1); + } + + await this.save(); +}); + +CommunitySchema.method('json', function json(): CommunityData { + return { + community_id: this.community_id, + name: this.name, + description: this.description, + icon: this.icon.replace(/[^A-Za-z0-9+/=\s]/g, ''), + icon_3ds: '', + pid: this.owner, + app_data: this.app_data.replace(/[^A-Za-z0-9+/=\s]/g, ''), + is_user_community: '0' + }; +}); + +export const Community = model('Community', CommunitySchema); \ No newline at end of file diff --git a/src/models/content.ts b/src/models/content.ts new file mode 100644 index 0000000..8818c39 --- /dev/null +++ b/src/models/content.ts @@ -0,0 +1,20 @@ +import { Schema, model } from 'mongoose'; +import { IContent, ContentModel } from '@/types/mongoose/content'; + +const ContentSchema = new Schema({ + pid: Number, + followed_communities: { + type: [String], + default: [0] + }, + followed_users: { + type: [Number], + default: [0] + }, + following_users: { + type: [Number], + default: [0] + } +}); + +export const Content = model('Content', ContentSchema); diff --git a/src/models/conversation.js b/src/models/conversation.js deleted file mode 100644 index a790363..0000000 --- a/src/models/conversation.js +++ /dev/null @@ -1,64 +0,0 @@ -const { Schema, model } = require('mongoose'); -const snowflake = require('node-snowflake').Snowflake; - -const ConversationSchema = new Schema({ - id: { - type: String, - default: snowflake.nextId() - }, - created_at: { - type: Date, - default: new Date(), - }, - last_message_sent: { - type: Date, - default: new Date(), - }, - message_preview: { - type: String, - default: "" - }, - pid1: { - pid: String, - official: { - type: Boolean, - default: false - }, - screen_name: String, - read: Boolean - }, - pid2: { - pid: String, - official: { - type: Boolean, - default: false - }, - screen_name: String, - read: Boolean - } -}); - -ConversationSchema.methods.newMessage = async function(message, fromPid) { - const pid1 = this.get('pid1'); - const pid2 = this.get('pid2'); - if(pid1.pid === fromPid) { - pid1.read = true - pid2.read = false - } - else { - pid1.read = false - pid2.read = true - } - this.set('pid1', pid1); - this.set('pid2', pid2); - this.set('last_message_sent', new Date()); - this.set('message_preview', message); - await this.save(); -} - -const CONVERSATION = model('CONVERSATION', ConversationSchema); - -module.exports = { - ConversationSchema: ConversationSchema, - CONVERSATION: CONVERSATION -}; diff --git a/src/models/conversation.ts b/src/models/conversation.ts new file mode 100644 index 0000000..4aaab7d --- /dev/null +++ b/src/models/conversation.ts @@ -0,0 +1,50 @@ +import { Schema, model } from 'mongoose'; +import { Snowflake } from 'node-snowflake'; +import { IConversation, IConversationMethods, ConversationModel, HydratedConversationDocument } from '@/types/mongoose/conversation'; + +const ConversationSchema = new Schema({ + id: { + type: String, + default: Snowflake.nextId() + }, + created_at: { + type: Date, + default: new Date(), + }, + last_updated: { + type: Date, + default: new Date(), + }, + message_preview: { + type: String, + default: '' + }, + users: [{ + pid: Number, + official: { + type: Boolean, + default: false + }, + read: { + type: Boolean, + default: true + } + }] +}); + +ConversationSchema.method('newMessage', async function newMessage(message: string, senderPID: number) { + if (this.users[0].pid === senderPID) { + this.users[1].read = false; + this.markModified('users[1].read'); + } else { + this.users[0].read = false; + this.markModified('users[0].read'); + } + + this.last_updated = new Date(); + this.message_preview = message; + + await this.save(); +}); + +export const Conversation = model('Conversation', ConversationSchema); \ No newline at end of file diff --git a/src/models/endpoint.js b/src/models/endpoint.js deleted file mode 100644 index ae4ac2a..0000000 --- a/src/models/endpoint.js +++ /dev/null @@ -1,33 +0,0 @@ -const { Schema, model } = require('mongoose'); - -const endpointSchema = new Schema({ - has_error: Number, - version: Number, - endpoint: { - host: String, - api_host: String, - portal_host: String, - n3ds_host: String - }, - guest: Boolean, -}); - -endpointSchema.methods.updateHosts = async function({host, api_host, portal_host, n3ds_host}) { - this.set('endpoint.host', host); - this.set('endpoint.api_host', api_host); - this.set('endpoint.portal_host', portal_host); - this.set('endpoint.n3ds_host', n3ds_host); - await this.save(); -}; - -endpointSchema.methods.updateGuest = async function(mode) { - this.set('guest', mode); - await this.save(); -} - -const ENDPOINT = model('ENDPOINT', endpointSchema); - -module.exports = { - endpointSchema, - ENDPOINT -}; diff --git a/src/models/endpoint.ts b/src/models/endpoint.ts new file mode 100644 index 0000000..bc57f56 --- /dev/null +++ b/src/models/endpoint.ts @@ -0,0 +1,15 @@ +import { Schema, model } from 'mongoose'; +import { IEndpoint, EndpointModel } from '@/types/mongoose/endpoint'; + +const endpointSchema = new Schema({ + status: Number, + server_access_level: String, + topics: Boolean, + guest_access: Boolean, + host: String, + api_host: String, + portal_host: String, + n3ds_host: String +}); + +export const Endpoint = model('Endpoint', endpointSchema); diff --git a/src/models/notification.ts b/src/models/notification.ts new file mode 100644 index 0000000..a4fd5dd --- /dev/null +++ b/src/models/notification.ts @@ -0,0 +1,17 @@ +import { Schema, model } from 'mongoose'; +import { INotification, NotificationModel } from '@/types/mongoose/notification'; + +const NotificationSchema = new Schema({ + pid: String, + type: String, + link: String, + objectID: String, + users: [{ + user: String, + timestamp: Date + }], + read: Boolean, + lastUpdated: Date +}); + +export const Notification = model('Notification', NotificationSchema); diff --git a/src/models/post.js b/src/models/post.js deleted file mode 100644 index 689e498..0000000 --- a/src/models/post.js +++ /dev/null @@ -1,115 +0,0 @@ -const { Schema, model } = require('mongoose'); - -const PostSchema = new Schema({ - title_id: String, - screen_name: String, - body: String, - app_data: String, - painting: String, - painting_uri: String, - screenshot: String, - url: String, - search_key: { - type: [String], - default: undefined - }, - topic_tag: { - type: [String], - default: undefined - }, - community_id: String, - country_id: Number, - created_at: Date, - feeling_id: Number, - id: String, - is_autopost: { - type: Number, - default: 0 - }, - is_community_private_autopost: { - type: Number, - default: 0 - }, - is_spoiler: { - type: Number, - default: 0 - }, - is_app_jumpable: { - type: Number, - default: 0 - }, - empathy_count: { - type: Number, - default: 0 - }, - language_id: { - type: Number, - default: 1 - }, - mii: String, - mii_face_url: String, - number: { - type: Number, - default: 1 - }, - pid: Number, - platform_id: Number, - region_id: Number, - parent_post: String, - reply_count: { - type: Number, - default: 0 - }, - verified: { - type: Boolean, - default: false - }, - parent: { - type: String, - default: null - }, - message_to_pid: { - type: String, - default: null - }, - conversation_id: { - type: String, - default: null - } -}); - - -PostSchema.methods.upEmpathy = async function() { - const empathy = this.get('empathy_count'); - this.set('empathy_count', empathy + 1); - - await this.save(); -}; - -PostSchema.methods.downEmpathy = async function() { - const empathy = this.get('empathy_count'); - this.set('empathy_count', empathy - 1); - - await this.save(); -}; - -PostSchema.methods.upReply = async function() { - const replyCount = this.get('reply_count'); - this.set('reply_count', replyCount + 1); - - await this.save(); -}; - -PostSchema.methods.downReply = async function() { - const replyCount = this.get('reply_count'); - this.set('reply_count', replyCount - 1); - - await this.save(); -}; - -const POST = model('POST', PostSchema); - -module.exports = { - PostSchema, - POST -}; diff --git a/src/models/post.ts b/src/models/post.ts new file mode 100644 index 0000000..663918a --- /dev/null +++ b/src/models/post.ts @@ -0,0 +1,216 @@ +import crypto from 'node:crypto'; +import moment from 'moment'; +import { Schema, model } from 'mongoose'; +import { HydratedPostDocument, IPost, IPostMethods, PostModel } from '@/types/mongoose/post'; +import { HydratedCommunityDocument } from '@/types/mongoose/community'; +import { PostToJSONOptions } from '@/types/mongoose/post-to-json-options'; +import { PostData, PostPainting, PostScreenshot, PostTopicTag } from '@/types/miiverse/post'; + +const PostSchema = new Schema({ + id: String, + title_id: String, + screen_name: String, + body: String, + app_data: String, + painting: String, + screenshot: String, + screenshot_length: Number, + search_key: { + type: [String], + default: undefined + }, + topic_tag: { + type: String, + default: undefined + }, + community_id: { + type: String, + default: undefined + }, + created_at: Date, + feeling_id: Number, + is_autopost: { + type: Number, + default: 0 + }, + is_community_private_autopost: { + type: Number, + default: 0 + }, + is_spoiler: { + type: Number, + default: 0 + }, + is_app_jumpable: { + type: Number, + default: 0 + }, + empathy_count: { + type: Number, + default: 0, + min: 0 + }, + country_id: { + type: Number, + default: 49 + }, + language_id: { + type: Number, + default: 1 + }, + mii: String, + mii_face_url: String, + pid: Number, + platform_id: Number, + region_id: Number, + parent: String, + reply_count: { + type: Number, + default: 0 + }, + verified: { + type: Boolean, + default: false + }, + message_to_pid: { + type: String, + default: null + }, + removed: { + type: Boolean, + default: false + }, + removed_reason: String, + yeahs: [Number], + number: Number +}, { + id: false // * Disables the .id() getter used by Mongoose in TypeScript. Needed to have our own .id field +}); + + +PostSchema.method('del', async function del(reason: string) { + this.removed = true; + this.removed_reason = reason; + await this.save(); +}); + +PostSchema.method('generatePostUID', async function generatePostUID(length: number) { + const id = Buffer.from(String.fromCharCode(...crypto.getRandomValues(new Uint8Array(length * 2))), 'binary').toString('base64').replace(/[+/]/g, '').substring(0, length); + + const inuse = await Post.findOne({ id }); + + if (inuse) { + await this.generatePostUID(length); + } else { + this.id = id; + } +}); + +PostSchema.method('cleanedBody', function cleanedBody(): string { + return this.body ? this.body.replace(/[^A-Za-z\d\s-_!@#$%^&*(){}+=,.<>/?;:'"[\]]/g, '').replace(/[\n\r]+/gm, '') : ''; +}); + +PostSchema.method('cleanedMiiData', function cleanedMiiData(): string { + return this.mii.replace(/[^A-Za-z0-9+/=]/g, '').replace(/[\n\r]+/gm, '').trim(); +}); + +PostSchema.method('cleanedPainting', function cleanedPainting(): string { + return this.painting.replace(/[\n\r]+/gm, '').trim(); +}); + +PostSchema.method('cleanedAppData', function cleanedAppData(): string { + return this.app_data.replace(/[^A-Za-z0-9+/=]/g, '').replace(/[\n\r]+/gm, '').trim(); +}); + +PostSchema.method('formatPainting', function formatPainting(): PostPainting | undefined { + if (this.painting) { + return { + format: 'tga', + content: this.cleanedPainting(), + size: this.painting.length, + url: `https://pretendo-cdn.b-cdn.net/paintings/${this.pid}/${this.id}.png` + }; + } +}); + +PostSchema.method('formatScreenshot', function formatScreenshot(): PostScreenshot | undefined { + if (this.screenshot && this.screenshot_length) { + return { + size: this.screenshot_length, + url: `https://pretendo-cdn.b-cdn.net/screenshots/${this.pid}/${this.id}.jpg` + }; + } +}); + +PostSchema.method('formatTopicTag', function formatTopicTag(): PostTopicTag | undefined { + if (this.topic_tag?.trim()) { + return { + name: this.topic_tag, + title_id: this.title_id + }; + } +}); + +PostSchema.method('json', function json(options: PostToJSONOptions, community?: HydratedCommunityDocument): PostData { + const post: PostData = { + app_data: undefined, // TODO - I try to keep these fields in the real order they show up in, but idk where this one goes + body: this.cleanedBody(), + community_id: this.community_id, // TODO - This sucks + country_id: this.country_id, + created_at: moment(this.created_at).format('YYYY-MM-DD HH:MM:SS'), + feeling_id: this.feeling_id, + id: this.id, + is_autopost: this.is_autopost ? 1 : 0, + is_community_private_autopost: this.is_community_private_autopost ? 1 : 0, + is_spoiler: this.is_spoiler ? 1 : 0, + is_app_jumpable: this.is_app_jumpable ? 1 : 0, + empathy_count: this.empathy_count || 0, + language_id: this.language_id, + mii: undefined, // * Conditionally set later + mii_face_url: undefined, // * Conditionally set later + number: 0, + painting: this.formatPainting(), + pid: this.pid, + platform_id: this.platform_id, + region_id: this.region_id, + reply_count: this.reply_count || 0, + screen_name: this.screen_name, + screenshot: this.formatScreenshot(), + topic_tag: undefined, // * Conditionally set later + title_id: this.title_id, + }; + + if (options.app_data) { + post.app_data = this.cleanedAppData(); + } + + if (options.with_mii) { + post.mii = this.cleanedMiiData(); + post.mii_face_url = this.mii_face_url; + } + + if (options.topic_tag) { + post.topic_tag = this.formatTopicTag(); + } + + if (community) { + post.community_id = community.community_id; + } + + // * Some sanity checks + if (post.feeling_id > 5) { + post.feeling_id = 0; + } + + return post; +}); + +PostSchema.pre('save', async function(next) { + if (!this.id) { + await this.generatePostUID(21); + } + + next(); +}); + +export const Post = model('Post', PostSchema); diff --git a/src/models/report.ts b/src/models/report.ts new file mode 100644 index 0000000..608b729 --- /dev/null +++ b/src/models/report.ts @@ -0,0 +1,14 @@ +import { Schema, model } from 'mongoose'; +import { IReport, ReportModel } from '@/types/mongoose/report'; + +const ReportSchema = new Schema({ + pid: String, + post_id: String, + reason: Number, + created_at: { + type: Date, + default: new Date() + } +}); + +export const Report = model('Report', ReportSchema); diff --git a/src/models/settings.ts b/src/models/settings.ts new file mode 100644 index 0000000..d3c7e03 --- /dev/null +++ b/src/models/settings.ts @@ -0,0 +1,59 @@ +import { Schema, model } from 'mongoose'; +import { SettingsData } from '@/types/miiverse/settings'; +import { HydratedSettingsDocument, ISettings, ISettingsMethods, SettingsModel } from '@/types/mongoose/settings'; + +const SettingsSchema = new Schema({ + pid: Number, + screen_name: String, + account_status: { + type: Number, + default: 0 + }, + ban_lift_date: Date, + ban_reason: String, + profile_comment: { + type: String, + default: undefined + }, + profile_comment_visibility: { + type: Boolean, + default: true + }, + game_skill: { + type: Number, + default: 0 + }, + game_skill_visibility: { + type: Boolean, + default: true + }, + birthday_visibility: { + type: Boolean, + default: false + }, + relationship_visibility: { + type: Boolean, + default: false + }, + country_visibility: { + type: Boolean, + default: false + }, + profile_favorite_community_visibility: { + type: Boolean, + default: true + }, + receive_notifications: { + type: Boolean, + default: true + } +}); + +SettingsSchema.method('json', function json(): SettingsData { + return { + pid: this.pid, + screen_name: this.screen_name + }; +}); + +export const Settings = model('Settings', SettingsSchema); diff --git a/src/models/user.js b/src/models/user.js deleted file mode 100644 index ade5e1a..0000000 --- a/src/models/user.js +++ /dev/null @@ -1,278 +0,0 @@ -const { Schema, model } = require('mongoose'); - -const notification = new Schema({ - content: String, - link: String, - read: Boolean, - created_at: Date, -}); - -const UserSchema = new Schema({ - pid: Number, - created_at: Date, - user_id: String, - pnid: String, - birthday: Date, - country: String, - pfp_uri: String, - mii: String, - mii_face_url: String, - /** - * Account Status - * 0 - Fine - * 1 - Limited from Posting - * 2 - Temporary Ban - * 3 - Forever Ban - */ - account_status: { - type: Number, - default: 0 - }, - ban_lift_date: Date, - ban_reason: String, - official: { - type: Boolean, - default: false - }, - profile_comment: { - type: String, - default: undefined - }, - game_skill: { - type: Number, - default: 0 - }, - game_skill_visibility: { - type: Boolean, - default: true - }, - profile_comment_visibility: { - type: Boolean, - default: true - }, - birthday_visibility: { - type: Boolean, - default: false - }, - relationship_visibility: { - type: Boolean, - default: false - }, - country_visibility: { - type: Boolean, - default: false - }, - profile_favorite_community_visibility: { - type: Boolean, - default: true - }, - notifications: { - type: Boolean, - default: false - }, - likes: { - type: [String], - default: [0] - }, - followed_communities: { - type: [String], - default: [0] - }, - followed_users: { - type: [String], - default: [0] - }, - following_users: { - type: [String], - default: [0] - }, - followers: { - type: Number, - default: 0 - }, - following: { - type: Number, - default: 0 - }, - notification_list: { - type: [notification], - default: [{ - content: 'This is your notifications! You\'ll see more stuff here soon!', - link: '/users/me', - read: false, - created_at: new Date(), - }] - } - -}); - -UserSchema.methods.getAccountStatus = async function() { - return this.get('account_status'); -}; - -UserSchema.methods.setAccountStatus = async function(accountStatus) { - this.set('account_status', accountStatus); - await this.save(); -}; -UserSchema.methods.getBanDate = async function() { - return this.get('ban_lift_date'); -}; - -UserSchema.methods.setBanData = async function(banDate) { - this.set('ban_lift_date', banDate); - await this.save(); -}; -UserSchema.methods.getProfileComment = async function() { - return this.get('profile_comment'); -}; -UserSchema.methods.setProfileComment = async function(profileComment) { - this.set('profile_comment', profileComment); - await this.save(); -}; - -UserSchema.methods.getGameSkill = async function() { - return this.get('game_skill'); -}; - -UserSchema.methods.setGameSkill = async function(gameSkill) { - this.set('game_skill', gameSkill); - await this.save(); -}; -UserSchema.methods.getGameSkillVisibility = async function() { - return this.get('game_skill_visibility'); -}; - -UserSchema.methods.setGameSkillVisibility = async function(gameSkillVisibility) { - this.set('game_skill_visibility', gameSkillVisibility); - await this.save(); -}; -UserSchema.methods.getProfileCommentVisibility = async function() { - return this.get('profile_comment_visibility'); -}; - -UserSchema.methods.setProfileCommentVisibility = async function(profileCommentVisibility) { - this.set('profile_comment_visibility', profileCommentVisibility); - await this.save(); -}; -UserSchema.methods.getBirthdayVisibility = async function() { - return this.get('birthday_visibility'); -}; - -UserSchema.methods.setBirthdayVisibility = async function(birthdayVisibility) { - this.set('birthday_visibility', birthdayVisibility); - await this.save(); -}; -UserSchema.methods.getRelationshipVisibility = async function() { - return this.get('relationship_visibility'); -}; - -UserSchema.methods.setRelationshipVisibility = async function(accountStatus) { - this.set('relationship_visibility', accountStatus); - await this.save(); -}; -UserSchema.methods.getFavoriteCommunityVisibility = async function() { - return this.get('profile_favorite_community_visibility'); -}; - -UserSchema.methods.setFavoriteCommunityVisibility = async function(favoriteCommunityVisibility) { - this.set('profile_favorite_community_visibility', favoriteCommunityVisibility); - await this.save(); -}; - -UserSchema.methods.getCountryVisibility = async function() { - return this.get('country_visibility'); -}; - -UserSchema.methods.setCountryVisibility = async function(countryVisibility) { - this.set('country_visibility', countryVisibility); - await this.save(); -}; - -UserSchema.methods.addToLikes = async function(postID) { - const likes = this.get('likes'); - likes.addToSet(postID); - await this.save(); -} - -UserSchema.methods.removeFromLike = async function(postID) { - const likes = this.get('likes'); - likes.pull(postID); - await this.save(); -} - -UserSchema.methods.addToCommunities = async function(postID) { - const communities = this.get('followed_communities'); - communities.addToSet(postID); - await this.upFollowing(); - await this.save(); -} - -UserSchema.methods.removeFromCommunities = async function(postID) { - const communities = this.get('followed_communities'); - communities.pull(postID); - await this.downFollowing(); - await this.save(); -} - -UserSchema.methods.addToUsers = async function(postID) { - const users = this.get('followed_users'); - users.addToSet(postID); - await this.upFollowing(); - await this.save(); -} - -UserSchema.methods.removeFromUsers = async function(postID) { - const users = this.get('followed_users'); - users.pull(postID); - await this.downFollowing(); - await this.save(); -} - -UserSchema.methods.addToFollowers = async function(postID) { - const users = this.get('following_users'); - users.addToSet(postID); - await this.upFollower(); - await this.save(); -} - -UserSchema.methods.removeFromFollowers = async function(postID) { - const users = this.get('following_users'); - users.pull(postID); - await this.downFollower(); - await this.save(); -} - -UserSchema.methods.upFollower = async function() { - const followers = this.get('followers'); - this.set('followers', followers + 1); - - await this.save(); -}; - -UserSchema.methods.downFollower = async function() { - const followers = this.get('followers'); - if(followers > 0) - this.set('followers', followers - 1); - await this.save(); -}; - -UserSchema.methods.upFollowing = async function() { - const following = this.get('following'); - this.set('following', following + 1); - - await this.save(); -}; - -UserSchema.methods.downFollowing = async function() { - const following = this.get('following'); - if(following > 0) - this.set('following', following - 1); - await this.save(); -}; - -const USER = model('USER', UserSchema); - -module.exports = { - UserSchema, - USER -}; diff --git a/src/server.js b/src/server.js deleted file mode 100644 index 005b3bb..0000000 --- a/src/server.js +++ /dev/null @@ -1,61 +0,0 @@ -process.title = 'Pretendo - Miiverse'; -const express = require('express'); -const morgan = require('morgan'); -const xmlparser = require('./middleware/xml-parser'); -const database = require('./database'); -const logger = require('./logger'); -const config = require('../config.json'); - -const { http: { port } } = config; -const app = express(); - -const miiverse = require('./services/miiverse-api'); - -app.set('etag', false); -app.disable('x-powered-by'); - -// Create router -logger.info('Setting up Middleware'); -app.use(morgan('dev')); -app.use(express.json()); - -app.use(express.urlencoded({ - extended: true, - limit: '5mb', - parameterLimit: 100000 -})); -app.use(xmlparser); - -// import the servers into one -app.use(miiverse); - -// 404 handler -logger.info('Creating 404 status handler'); -app.use((request, response) => { - //logger.warn(request.protocol + '://' + request.get('host') + request.originalUrl); - response.status(404); - response.send(); -}); - -// non-404 error handler -logger.info('Creating non-404 status handler'); -app.use((error, request, response) => { - const status = error.status || 500; - - response.status(status); - - response.json({ - app: 'api', - status, - error: error.message - }); -}); - -// Starts the server -logger.info('Starting server'); - -database.connect().then(() => { - app.listen(port, () => { - logger.success(`Server started on port ${port}`); - }); -}); \ No newline at end of file diff --git a/src/server.ts b/src/server.ts new file mode 100644 index 0000000..bc34398 --- /dev/null +++ b/src/server.ts @@ -0,0 +1,81 @@ +process.title = 'Pretendo - Miiverse'; + +import express from 'express'; +import morgan from 'morgan'; +import xmlbuilder from 'xmlbuilder'; +import { connect as connectDatabase } from '@/database'; +import { LOG_INFO, LOG_SUCCESS } from '@/logger'; +import auth from '@/middleware/auth'; + +import discovery from '@/services/discovery'; +import api from '@/services/api'; + +import { config } from '@/config-manager'; + +const { http: { port } } = config; +const app = express(); + +app.set('etag', false); +app.disable('x-powered-by'); + +// Create router +LOG_INFO('Setting up Middleware'); +app.use(morgan('dev')); +app.use(express.json()); + +app.use(express.urlencoded({ + extended: true, + limit: '5mb', + parameterLimit: 100000 +})); +app.use(auth); + +// import the servers into one +app.use(discovery); +app.use(api); + +// 404 handler +LOG_INFO('Creating 404 status handler'); +app.use((_request: express.Request, response: express.Response) => { + response.type('application/xml'); + response.status(404); + + return response.send(xmlbuilder.create({ + result: { + has_error: 1, + version: 1, + code: 404, + message: 'Not Found' + } + }).end({ pretty: true })); +}); + +// non-404 error handler +LOG_INFO('Creating non-404 status handler'); +app.use((_error: unknown, _request: express.Request, response: express.Response, _next: express.NextFunction) => { + const status = 500; + response.type('application/xml'); + response.status(404); + + return response.send(xmlbuilder.create({ + result: { + has_error: 1, + version: 1, + code: status, + message: 'Not Found' + } + }).end({ pretty: true })); +}); + +async function main(): Promise { + // Starts the server + LOG_INFO('Starting server'); + + await connectDatabase(); + + app.listen(port, () => { + LOG_SUCCESS(`Server started on port ${port}`); + }); +} + +main().catch(console.error); \ No newline at end of file diff --git a/src/services/api/index.ts b/src/services/api/index.ts new file mode 100644 index 0000000..005cf53 --- /dev/null +++ b/src/services/api/index.ts @@ -0,0 +1,35 @@ +import express from 'express'; +import subdomain from 'express-subdomain'; +import { LOG_INFO } from '@/logger'; + +import postsHandlers from '@/services/api/routes/posts'; +import friendMessagesHandlers from '@/services/api/routes/friend_messages'; +import communitiesHandlers from '@/services/api/routes/communities'; +import peopleHandlers from '@/services/api/routes/people'; +import topicsHandlers from '@/services/api/routes/topics'; +import usersHandlers from '@/services/api/routes/users'; +import statusHandlers from '@/services/api/routes/status'; + +// Main router for endpointsindex.js +const router = express.Router(); + +// Router to handle the subdomain restriction +const api = express.Router(); + +// Create subdomains +LOG_INFO('[MIIVERSE] Creating \'api\' subdomain'); +router.use(subdomain('api.olv', api)); +router.use(subdomain('api-test.olv', api)); +router.use(subdomain('api-dev.olv', api)); + +// Setup routes +api.use('/v1/posts', postsHandlers); +api.use('/v1/posts.search', postsHandlers); +api.use('/v1/friend_messages', friendMessagesHandlers); +api.use('/v1/communities/', communitiesHandlers); +api.use('/v1/people/', peopleHandlers); +api.use('/v1/topics/', topicsHandlers); +api.use('/v1/users/', usersHandlers); +api.use('/v1/status/', statusHandlers); + +export default router; \ No newline at end of file diff --git a/src/services/api/routes/communities.ts b/src/services/api/routes/communities.ts new file mode 100644 index 0000000..3dfc260 --- /dev/null +++ b/src/services/api/routes/communities.ts @@ -0,0 +1,481 @@ +import express from 'express'; +import xmlbuilder from 'xmlbuilder'; +import multer from 'multer'; +import { z } from 'zod'; +import { + getMostPopularCommunities, + getNewCommunities, + getCommunityByTitleID, + getUserContent, +} from '@/database'; +import { getValueFromQueryString } from '@/util'; +import { LOG_WARN } from '@/logger'; +import { Community } from '@/models/community'; +import { Post } from '@/models/post'; +import { HydratedCommunityDocument } from '@/types/mongoose/community'; +import { SubCommunityQuery } from '@/types/mongoose/subcommunity-query'; +import { CommunityPostsQuery } from '@/types/mongoose/community-posts-query'; +import { HydratedPostDocument, IPost } from '@/types/mongoose/post'; +import { ParamPack } from '@/types/common/param-pack'; +import { CommunitiesResult, CommunityPostsResult } from '@/types/miiverse/community'; + +const createNewCommunitySchema = z.object({ + name: z.string(), + description: z.string().optional(), + icon: z.string(), + app_data: z.string().optional() +}); + +const router = express.Router(); + +function respondCommunityError(response: express.Response, httpStatusCode: number, errorCode: number): void { + response.status(httpStatusCode).send(xmlbuilder.create({ + result: { + has_error: 1, + version: 1, + code: httpStatusCode, + error_code: errorCode, + message: 'COMMUNITY_ERROR' // This field is unused by the entire nn_olv.rpl + } + }).end({ pretty: true })); +} + +function respondCommunityNotFound(response: express.Response): void { + respondCommunityError(response, 404, 919); +} + +async function commonGetSubCommunity(paramPack: ParamPack, communityID: string | undefined): Promise { + + const parentCommunity = await getCommunityByTitleID(paramPack.title_id); + + if (!parentCommunity) { + return null; + } + + const query = { + parent: parentCommunity.olive_community_id, + community_id: communityID + }; + + const community = await Community.findOne(query); + + if (!community) { + return null; + } + + return community; +} + +/* GET post titles. */ +router.get('/', async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + const parentCommunity = await getCommunityByTitleID(request.paramPack.title_id); + if (!parentCommunity) { + respondCommunityNotFound(response); + return; + } + + const type = getValueFromQueryString(request.query, 'type')[0]; + const limitString = getValueFromQueryString(request.query, 'limit')[0]; + + let limit = 4; + + if (limitString) { + limit = parseInt(limitString); + } + + if (isNaN(limit)) { + limit = 4; + } + + if (limit > 16) { + limit = 16; + } + + const query: SubCommunityQuery = { + parent: parentCommunity.olive_community_id + }; + + if (type === 'my') { + query.owner = request.pid; + } else if (type === 'favorite') { + query.user_favorites = request.pid; + } + + const communities = await Community.find(query).limit(limit); + + const result: CommunitiesResult = { + has_error: 0, + version: 1, + request_name: 'communities', + communities: [] + }; + + for (const community of communities) { + result.communities.push({ + community: community.json() + }); + } + + response.send(xmlbuilder.create({ + result + }, { + separateArrayItems: true + }).end({ + pretty: true, + allowEmpty: true + })); +}); + +router.get('/popular', async function (_request: express.Request, response: express.Response): Promise { + const popularCommunities = await getMostPopularCommunities(100); + + response.type('application/json'); + response.send(popularCommunities); +}); + +router.get('/new', async function (_request: express.Request, response: express.Response): Promise { + const newCommunities = await getNewCommunities(100); + + response.type('application/json'); + response.send(newCommunities); +}); + +router.get('/:communityID/posts', async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + let community = await Community.findOne({ + community_id: request.params.communityID + }); + + if (!community) { + community = await getCommunityByTitleID(request.paramPack.title_id); + } + + if (!community) { + return respondCommunityNotFound(response); + } + + const query: CommunityPostsQuery = { + community_id: community.olive_community_id, + removed: false, + app_data: { $ne: null }, + message_to_pid: { $eq: null } + }; + + const searchKey = getValueFromQueryString(request.query, 'search_key')[0]; + const allowSpoiler = getValueFromQueryString(request.query, 'allow_spoiler')[0]; + const postType = getValueFromQueryString(request.query, 'type')[0]; + const queryBy = getValueFromQueryString(request.query, 'by')[0]; + const distinctPID = getValueFromQueryString(request.query, 'distinct_pid')[0]; + const limitString = getValueFromQueryString(request.query, 'limit')[0]; + const withMii = getValueFromQueryString(request.query, 'with_mii')[0]; + + let limit = 10; + + if (limitString) { + limit = parseInt(limitString); + } + + if (isNaN(limit)) { + limit = 10; + } + + if (searchKey) { + query.search_key = searchKey; + } + + if (!allowSpoiler) { + query.is_spoiler = 0; + } + + //TODO: There probably is a type for text and screenshots too, will have to investigate + if (postType === 'memo') { + query.painting = { $ne: null }; + } + + if (queryBy === 'followings') { + const userContent = await getUserContent(request.pid); + + if (!userContent) { + LOG_WARN(`USER PID ${request.pid} HAS NO USER CONTENT`); + query.pid = []; + } else { + query.pid = userContent.following_users; + } + } else if (queryBy === 'self') { + query.pid = request.pid; + } + + let posts: HydratedPostDocument[]; + + if (distinctPID && distinctPID === '1') { + const unhydratedPosts = await Post.aggregate([ + { $match: query }, // filter based on input query + { $sort: { created_at: -1 } }, // sort by 'created_at' in descending order + { $group: { _id: '$pid', doc: { $first: '$$ROOT' } } }, // remove any duplicate 'pid' elements + { $replaceRoot: { newRoot: '$doc' } }, // replace the root with the 'doc' field + { $limit: limit } // only return the top 10 results + ]); + posts = unhydratedPosts.map((post: IPost) => Post.hydrate(post)); + } else { + posts = await Post.find(query).sort({ created_at: -1 }).limit(limit); + } + + const result: CommunityPostsResult = { + has_error: 0, + version: 1, + request_name: 'posts', + topic: { + community_id: community.community_id + }, + posts: [] + }; + + for (const post of posts) { + result.posts.push({ + post: post.json({ + with_mii: withMii === '1', + app_data: true, + topic_tag: true + }) + }); + } + + response.send(xmlbuilder.create({ + result + }, { + separateArrayItems: true + }).end({ + pretty: true, + allowEmpty: true + })); +}); + +// Handler for POST on '/v1/communities' +router.post('/', multer().none(), async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + const parentCommunity = await getCommunityByTitleID(request.paramPack.title_id); + if (!parentCommunity) { + return respondCommunityNotFound(response); + } + + // TODO - Better error codes, maybe do defaults? + const bodyCheck = createNewCommunitySchema.safeParse(request.body); + if (!bodyCheck.success) { + return respondCommunityError(response, 400, 20); + } + + request.body.name = request.body.name.trim(); + request.body.icon = request.body.icon.trim(); + + if (request.body.description) { + request.body.description = request.body.description.trim(); + } + + if (request.body.app_data) { + request.body.app_data = request.body.app_data.trim(); + } + + // Name must be at least 4 character long + if (request.body.name.length < 4) { + return respondCommunityError(response, 400, 20); + } + + // Each user can only have 4 subcommunities per title + const ownedQuery = { + parent: parentCommunity.olive_community_id, + owner: request.pid + }; + + const ownedSubcommunityCount = await Community.countDocuments(ownedQuery); + if (ownedSubcommunityCount >= 4) { + return respondCommunityError(response, 401, 911); + } + + // Each user can only have 16 favorite subcommunities per title + const favoriteQuery = { + parent: parentCommunity.olive_community_id, + user_favorites: request.pid + }; + + const ownedFavoriteCount = await Community.countDocuments(favoriteQuery); + if (ownedFavoriteCount >= 16) { + return respondCommunityError(response, 401, 912); + } + + const communitiesCount = await Community.count(); + const communityID = (parseInt(parentCommunity.community_id) + (5000 * communitiesCount)); // Change this to auto increment + const community = await Community.create({ + platform_id: 0, // WiiU + name: request.body.name, + description: request.body.description || '', + open: true, + allows_comments: true, + type: 1, + parent: parentCommunity.olive_community_id, + admins: parentCommunity.admins, + owner: request.pid, + icon: request.body.icon, + title_id: request.paramPack.title_id, + community_id: communityID.toString(), + olive_community_id: communityID.toString(), + app_data: request.body.app_data || '', + user_favorites: [request.pid] + }); + + response.send(xmlbuilder.create({ + result: { + has_error: '0', + version: '1', + request_name: 'community', + community: community.json() + } + }).end({ + pretty: true, + allowEmpty: true + })); +}); + +router.post('/:community_id.delete', multer().none(), async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + const community = await commonGetSubCommunity(request.paramPack, request.params.community_id); + + if (!community) { + respondCommunityNotFound(response); + return; + } + + if (community.owner != request.pid) { + response.sendStatus(403); // Forbidden + return; + } + + await Community.deleteOne({ _id: community._id }); + + response.send(xmlbuilder.create({ + result: { + has_error: '0', + version: '1', + request_name: 'community', + community: community.json() + } + }).end({ pretty: true, allowEmpty: true })); +}); + +router.post('/:community_id.favorite', multer().none(), async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + const community = await commonGetSubCommunity(request.paramPack, request.params.community_id); + + if (!community) { + respondCommunityNotFound(response); + return; + } + + // Each user can only have 16 favorite subcommunities per title + const favoriteQuery = { + parent: community.parent, + user_favorites: request.pid + }; + + const ownedFavoriteCount = await Community.countDocuments(favoriteQuery); + if (ownedFavoriteCount >= 16) { + return respondCommunityError(response, 401, 914); + } + + await community.addUserFavorite(request.pid); + + response.send(xmlbuilder.create({ + result: { + has_error: '0', + version: '1', + request_name: 'community', + community: community.json() + } + }).end({ + pretty: true, + allowEmpty: true + })); +}); + +router.post('/:community_id.unfavorite', multer().none(), async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + const community = await commonGetSubCommunity(request.paramPack, request.params.community_id); + if (!community) { + respondCommunityNotFound(response); + return; + } + + // You can't remove from your favorites a community you own + if (community.owner === request.pid) { + return respondCommunityError(response, 401, 916); + } + + await community.delUserFavorite(request.pid); + + response.send(xmlbuilder.create({ + result: { + has_error: '0', + version: '1', + request_name: 'community', + community: community.json() + } + }).end({ + pretty: true, + allowEmpty: true + })); +}); + + +router.post('/:community_id', multer().none(), async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + const community = await commonGetSubCommunity(request.paramPack, request.params.community_id); + + if (!community) { + respondCommunityNotFound(response); + return; + } + + if (community.owner != request.pid) { + response.sendStatus(403); // Forbidden + return; + } + + if (request.body.name) { + community.name = request.body.name.trim(); + } + + if (request.body.description) { + community.description = request.body.description.trim(); + } + + if (request.body.icon) { + community.icon = request.body.icon.trim(); + } + + if (request.body.app_data) { + community.app_data = request.body.app_data.trim(); + } + + await community.save(); + + response.send(xmlbuilder.create({ + result: { + has_error: '0', + version: '1', + request_name: 'community', + community: community.json() + } + }).end({ + pretty: true, + allowEmpty: true + })); +}); + +export default router; diff --git a/src/services/api/routes/friend_messages.ts b/src/services/api/routes/friend_messages.ts new file mode 100644 index 0000000..f5d0051 --- /dev/null +++ b/src/services/api/routes/friend_messages.ts @@ -0,0 +1,300 @@ +import express from 'express'; +import multer from 'multer'; +import { Snowflake } from 'node-snowflake'; +import moment from 'moment'; +import xmlbuilder from 'xmlbuilder'; +import { z } from 'zod'; +import { GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc'; +import { getUserFriendPIDs, getUserAccountData, processPainting, uploadCDNAsset, getValueFromQueryString } from '@/util'; +import { getConversationByUsers, getUserSettings, getFriendMessages } from '@/database'; +import { LOG_WARN } from '@/logger'; +import { Post } from '@/models/post'; +import { Conversation } from '@/models/conversation'; +import { FormattedMessage } from '@/types/common/formatted-message'; + +const sendMessageSchema = z.object({ + message_to_pid: z.string().transform(Number), + body: z.string(), + painting: z.string().optional(), + screenshot: z.string().optional(), + app_data: z.string().optional() +}); + +const router = express.Router(); +const upload = multer(); + +router.post('/', upload.none(), async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + // TODO - Better error codes, maybe do defaults? + const bodyCheck = sendMessageSchema.safeParse(request.body); + + if (!bodyCheck.success) { + response.status(422); + return; + } + + const recipientPID = bodyCheck.data.message_to_pid; + let messageBody = bodyCheck.data.body; + const painting = bodyCheck.data.painting?.replace(/\0/g, '').trim() || ''; + const screenshot = bodyCheck.data.screenshot?.trim().replace(/\0/g, '').trim() || ''; + const appData = bodyCheck.data.app_data?.replace(/[^A-Za-z0-9+/=\s]/g, '').trim() || ''; + + if (isNaN(recipientPID)) { + response.status(422); + return; + } + + let sender: GetUserDataResponse; + + try { + sender = await getUserAccountData(request.pid); + } catch (error) { + // TODO - Log this error + response.status(422); + return; + } + + if (!sender.mii) { + // * This should never happen, but TypeScript complains so check anyway + // TODO - Better errors + response.status(422); + return; + } + + let recipient: GetUserDataResponse; + + try { + recipient = await getUserAccountData(request.pid); + } catch (error) { + // TODO - Log this error + response.status(422); + return; + } + + let conversation = await getConversationByUsers([sender.pid, recipient.pid]); + + if (!conversation) { + const userSettings = await getUserSettings(request.pid); + const user2Settings = await getUserSettings(recipient.pid); + + if (!sender || !recipient || userSettings || user2Settings) { + response.sendStatus(422); + return; + } + + conversation = await Conversation.create({ + id: Snowflake.nextId(), + users: [ + { + pid: sender.pid, + official: (sender.accessLevel === 2 || sender.accessLevel === 3), + read: true + }, + { + pid: recipient.pid, + official: (recipient.accessLevel === 2 || recipient.accessLevel === 3), + read: false + }, + ] + }); + } + + if (!conversation) { + response.sendStatus(404); + return; + } + + const friendPIDs = await getUserFriendPIDs(recipient.pid); + + if (friendPIDs.indexOf(request.pid) === -1) { + response.sendStatus(422); + return; + } + + let miiFace = 'normal_face.png'; + switch (parseInt(request.body.feeling_id)) { + case 1: + miiFace = 'smile_open_mouth.png'; + break; + case 2: + miiFace = 'wink_left.png'; + break; + case 3: + miiFace = 'surprise_open_mouth.png'; + break; + case 4: + miiFace = 'frustrated.png'; + break; + case 5: + miiFace = 'sorrow.png'; + break; + } + + if (messageBody) { + messageBody = messageBody.replace(/[^A-Za-z\d\s-_!@#$%^&*(){}‛¨ƒºª«»“”„¿¡←→↑↓√§¶†‡¦–—⇒⇔¤¢€£¥™©®+×÷=±∞ˇ˘˙¸˛˜′″µ°¹²³♭♪•…¬¯‰¼½¾♡♥●◆■▲▼☆★♀♂,./?;:'"\\<>]/g, ''); + } + + if (messageBody.length > 280) { + messageBody = messageBody.substring(0, 280); + } + + if (messageBody === '' && painting === '' && screenshot === '') { + response.status(422); + response.redirect(`/friend_messages/${conversation.id}`); + return; + } + + const post = await Post.create({ + title_id: request.paramPack.title_id, + community_id: conversation.id, + screen_name: sender.mii.name, + body: messageBody, + app_data: appData, + painting: painting, + screenshot: '', + screenshot_length: 0, + country_id: request.paramPack.country_id, + created_at: new Date(), + feeling_id: request.body.feeling_id, + search_key: request.body.search_key, + topic_tag: request.body.topic_tag, + is_autopost: request.body.is_autopost, + is_spoiler: (request.body.spoiler) ? 1 : 0, + is_app_jumpable: request.body.is_app_jumpable, + language_id: request.body.language_id, + mii: sender.mii.data, + mii_face_url: `https://mii.olv.pretendo.cc/mii/${sender.pid}/${miiFace}`, + pid: request.pid, + platform_id: request.paramPack.platform_id, + region_id: request.paramPack.region_id, + verified: (sender.accessLevel === 2 || sender.accessLevel === 3), + message_to_pid: request.body.message_to_pid, + parent: null, + removed: false + }); + + if (painting) { + const paintingBuffer = await processPainting(painting); + + if (paintingBuffer) { + await uploadCDNAsset('pn-cdn', `paintings/${request.pid}/${post.id}.png`, paintingBuffer, 'public-read'); + } else { + LOG_WARN(`PAINTING FOR POST ${post.id} FAILED TO PROCESS`); + } + } + + if (screenshot) { + const screenshotBuffer = Buffer.from(screenshot, 'base64'); + + await uploadCDNAsset('pn-cdn', `screenshots/${request.pid}/${post.id}.jpg`, screenshotBuffer, 'public-read'); + + post.screenshot = `/screenshots/${request.pid}/${post.id}.jpg`; + post.screenshot_length = screenshot.length; + + await post.save(); + } + + let postPreviewText = messageBody; + if (painting) { + postPreviewText = 'sent a Drawing'; + } else if (messageBody.length > 25) { + postPreviewText = messageBody.substring(0, 25) + '...'; + } + + await conversation.newMessage(postPreviewText, recipientPID); + + response.sendStatus(200); +}); + +router.get('/', async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + const limitString = getValueFromQueryString(request.query, 'limit')[0]; + + // TODO - Is this the limit? + let limit = 10; + + if (limitString) { + limit = parseInt(limitString); + } + + if (isNaN(limit)) { + limit = 10; + } + + if (!request.query.search_key) { + response.sendStatus(404); + return; + } + + const searchKey = getValueFromQueryString(request.query, 'search_key'); + + const messages = await getFriendMessages(request.pid.toString(), searchKey, limit); + + const postBody: FormattedMessage[] = []; + for (const message of messages) { + postBody.push({ + post: { + body: message.body, + country_id: message.country_id || 0, + created_at: moment(message.created_at).format('YYYY-MM-DD HH:MM:SS'), + feeling_id: message.feeling_id || 0, + id: message.id, + is_autopost: message.is_autopost, + is_spoiler: message.is_spoiler, + is_app_jumpable: message.is_app_jumpable, + empathy_added: message.empathy_count, + language_id: message.language_id, + message_to_pid: message.message_to_pid, + mii: message.mii, + mii_face_url: message.mii_face_url, + number: message.number || 0, + pid: message.pid, + platform_id: message.platform_id || 0, + region_id: message.region_id || 0, + reply_count: message.reply_count, + screen_name: message.screen_name, + topic_tag: { + name: message.topic_tag, + title_id: 0 + }, + title_id: message.title_id + } + }); + } + + response.send(xmlbuilder.create({ + result: { + has_error: 0, + version: 1, + request_name: 'friend_messages', + posts: postBody + } + }, { separateArrayItems: true }).end({ pretty: true })); +}); + +router.post('/:post_id/empathies', upload.none(), async function (_request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + // TODO - FOR JEMMA! FIX THIS! MISSING MONGOOSE SCHEMA METHODS + // * Remove the underscores from request and response to make them seen by eslint again + /* + let pid = getPIDFromServiceToken(req.headers["x-nintendo-servicetoken"]); + const post = await getPostByID(req.params.post_id); + if(pid === null) { + res.sendStatus(403); + return; + } + let user = await getUserByPID(pid); + if(user.likes.indexOf(post.id) === -1 && user.id !== post.pid) + { + post.upEmpathy(); + user.addToLikes(post.id) + res.sendStatus(200); + } + else + res.sendStatus(403); + */ +}); + +export default router; \ No newline at end of file diff --git a/src/services/api/routes/people.ts b/src/services/api/routes/people.ts new file mode 100644 index 0000000..b372893 --- /dev/null +++ b/src/services/api/routes/people.ts @@ -0,0 +1,151 @@ +import express from 'express'; +import xmlbuilder from 'xmlbuilder'; +import moment from 'moment'; +import { getUserContent, getFollowedUsers } from '@/database'; +import { getValueFromQueryString, getUserFriendPIDs } from '@/util'; +import { Post } from '@/models/post'; +import { CommunityPostsQuery } from '@/types/mongoose/community-posts-query'; +import { HydratedPostDocument, IPost } from '@/types/mongoose/post'; +import { PeopleFollowingResult, PeoplePostsResult } from '@/types/miiverse/people'; + +const router = express.Router(); + +/* GET post titles. */ +router.get('/', async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + const userContent = await getUserContent(request.pid); + + if (!userContent) { + response.sendStatus(404); + return; + } + + const query: CommunityPostsQuery = { + removed: false, + is_spoiler: 0, + app_data: { $eq: null }, + parent: { $eq: null }, + message_to_pid: { $eq: null } + }; + + const relation = getValueFromQueryString(request.query, 'relation')[0]; + const distinctPID = getValueFromQueryString(request.query, 'distinct_pid')[0]; + const limitString = getValueFromQueryString(request.query, 'limit')[0]; + const withMii = getValueFromQueryString(request.query, 'with_mii')[0]; + + let limit = 10; + + if (limitString) { + limit = parseInt(limitString); + } + + if (isNaN(limit)) { + limit = 10; + } + + if (relation === 'friend') { + query.pid = { $in: await getUserFriendPIDs(request.pid) }; + } else if (relation === 'following') { + query.pid = { $in: userContent.followed_users }; + } else if (request.query.pid) { + const pidInputs = getValueFromQueryString(request.query, 'pid'); + const pids = pidInputs.map(pid => Number(pid)).filter(pid => !isNaN(pid)); + + query.pid = { $in: pids }; + } + + let posts: HydratedPostDocument[]; + + if (distinctPID === '1') { + const unhydratedPosts = await Post.aggregate([ + { $match: query }, // filter based on input query + { $sort: { created_at: -1 } }, // sort by 'created_at' in descending order + { $group: { _id: '$pid', doc: { $first: '$$ROOT' } } }, // remove any duplicate 'pid' elements + { $replaceRoot: { newRoot: '$doc' } }, // replace the root with the 'doc' field + { $limit: limit } // only return the top 10 results + ]); + + posts = unhydratedPosts.map((post: IPost) => Post.hydrate(post)); + } else if (request.query.is_hot === '1') { + posts = await Post.find(query).sort({ empathy_count: -1}).limit(limit); + } else { + posts = await Post.find(query).sort({ created_at: -1}).limit(limit); + } + + const result: PeoplePostsResult = { + has_error: 0, + version: 1, + expire: moment().add(1, 'days').format('YYYY-MM-DD HH:MM:SS'), + request_name: 'posts', + people: [] + }; + + for (const post of posts) { + result.people.push({ + person: { + posts: [ + { + post: post.json({ + with_mii: withMii === '1', + topic_tag: true + }) + } + ] + } + }); + } + + response.send(xmlbuilder.create({ + result + }, { + separateArrayItems: true + }).end({ + pretty: true, + allowEmpty: true + })); +}); + +router.get('/:pid/following', async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + const pid = parseInt(request.params.pid); + + if (isNaN(pid)) { + response.sendStatus(404); + return; + } + + const userContent = await getUserContent(pid); + + if (!userContent) { + response.sendStatus(404); + return; + } + + const people = await getFollowedUsers(userContent); + + const result: PeopleFollowingResult = { + has_error: 0, + version: 1, + request_name: 'user_infos', + people: [] + }; + + for (const person of people) { + result.people.push({ + person: person.json() + }); + } + + response.send(xmlbuilder.create({ + result + }, { + separateArrayItems: true + }).end({ + pretty: true, + allowEmpty: true + })); +}); + +export default router; \ No newline at end of file diff --git a/src/services/api/routes/posts.ts b/src/services/api/routes/posts.ts new file mode 100644 index 0000000..ede2dfd --- /dev/null +++ b/src/services/api/routes/posts.ts @@ -0,0 +1,421 @@ +import express from 'express'; +import multer from 'multer'; +import xmlbuilder from 'xmlbuilder'; +import { z } from 'zod'; +import { GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc'; +import { getUserAccountData, processPainting, uploadCDNAsset, getValueFromQueryString } from '@/util'; +import { + getPostByID, + getUserContent, + getPostReplies, + getUserSettings, + getCommunityByID, + getCommunityByTitleID, + getDuplicatePosts +} from '@/database'; +import { LOG_WARN } from '@/logger'; +import { Post } from '@/models/post'; +import { Community } from '@/models/community'; +import { HydratedPostDocument } from '@/types/mongoose/post'; +import { PostRepliesResult } from '@/types/miiverse/post'; + +const newPostSchema = z.object({ + community_id: z.string().optional(), + app_data: z.string().optional(), + painting: z.string().optional(), + screenshot: z.string().optional(), + body: z.string().optional(), + feeling_id: z.string(), + search_key: z.string().array().or(z.string()).optional(), + topic_tag: z.string().optional(), + is_autopost: z.string(), + is_spoiler: z.string().optional(), + is_app_jumpable: z.string().optional(), + language_id: z.string() +}); + +const router = express.Router(); +const upload = multer(); + +/* GET post titles. */ +router.post('/', upload.none(), newPost); + +router.post('/:post_id/replies', upload.none(), newPost); + +router.post('/:post_id.delete', async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + const post = await getPostByID(request.params.post_id); + const userContent = await getUserContent(request.pid); + + if (!post || !userContent) { + response.sendStatus(504); + return; + } + + if (post.pid === userContent.pid) { + await post.del('User requested removal'); + response.sendStatus(200); + } else { + response.sendStatus(401); + } +}); + +router.post('/:post_id/empathies', upload.none(), async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + const post = await getPostByID(request.params.post_id); + + if (!post) { + response.sendStatus(404); + return; + } + + if (post.yeahs?.indexOf(request.pid) === -1) { + await Post.updateOne({ + id: post.id, + yeahs: { + $ne: request.pid + } + }, + { + $inc: { + empathy_count: 1 + }, + $push: { + yeahs: request.pid + } + }); + } else if (post.yeahs?.indexOf(request.pid) !== -1) { + await Post.updateOne({ + id: post.id, + yeahs: { + $eq: request.pid + } + }, + { + $inc: { + empathy_count: -1 + }, + $pull: { + yeahs: request.pid + } + }); + } + + response.sendStatus(200); +}); + +router.get('/:post_id/replies', async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + const limitString = getValueFromQueryString(request.query, 'limit')[0]; + + let limit = 10; // TODO - Is there a real limit? + + if (limitString) { + limit = parseInt(limitString); + } + + if (isNaN(limit)) { + limit = 10; + } + + const post = await getPostByID(request.params.post_id); + + if (!post) { + response.sendStatus(404); + return; + } + + const posts = await getPostReplies(post.id, limit); + if (posts.length === 0) { + response.sendStatus(404); + return; + } + + const result: PostRepliesResult = { + has_error: 0, + version: 1, + request_name: 'replies', + posts: [] + }; + + for (const post of posts) { + result.posts.push({ + post: post.json({ + with_mii: request.query.with_mii as string === '1', + topic_tag: true + }) + }); + } + + response.send(xmlbuilder.create({ + result + }, { + separateArrayItems: true + }).end({ + pretty: true, + allowEmpty: true + })); +}); + +router.get('/', async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + const postID = getValueFromQueryString(request.query, 'post_id')[0]; + + if (!postID) { + response.type('application/xml'); + response.status(404); + response.send(xmlbuilder.create({ + result: { + has_error: 1, + version: 1, + code: 404, + message: 'Not Found' + } + }).end({ pretty: true })); + return; + } + + const post = await getPostByID(postID); + + if (!post) { + response.status(404); + response.send(xmlbuilder.create({ + result: { + has_error: 1, + version: 1, + code: 404, + message: 'Not Found' + } + }).end({ pretty: true })); + return; + } + + response.send(xmlbuilder.create({ + result: { + has_error: '0', + version: '1', + request_name: 'posts.search', + posts: { + post: post.json({ with_mii: true }) + } + } + }).end({ pretty: true, allowEmpty: true })); +}); + +async function newPost(request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + let user: GetUserDataResponse; + + try { + user = await getUserAccountData(request.pid); + } catch (error) { + // TODO - Log this error + response.sendStatus(403); + return; + } + + if (!user.mii) { + // * This should never happen, but TypeScript complains so check anyway + // TODO - Better errors + response.status(422); + return; + } + + const userSettings = await getUserSettings(request.pid); + const bodyCheck = newPostSchema.safeParse(request.body); + + if (!userSettings || !bodyCheck.success) { + response.sendStatus(403); + return; + } + + const communityID = bodyCheck.data.community_id || ''; + let messageBody = bodyCheck.data.body; + const painting = bodyCheck.data.painting?.replace(/\0/g, '').trim() || ''; + const screenshot = bodyCheck.data.screenshot?.replace(/\0/g, '').trim() || ''; + const appData = bodyCheck.data.app_data?.replace(/[^A-Za-z0-9+/=\s]/g, '').trim() || ''; + const feelingID = parseInt(bodyCheck.data.feeling_id); + let searchKey = bodyCheck.data.search_key || []; + const topicTag = bodyCheck.data.topic_tag || ''; + const autopost = bodyCheck.data.is_autopost; + const spoiler = bodyCheck.data.is_spoiler; + const jumpable = bodyCheck.data.is_app_jumpable; + const languageID = parseInt(bodyCheck.data.language_id); + const countryID = parseInt(request.paramPack.country_id); + const platformID = parseInt(request.paramPack.platform_id); + const regionID = parseInt(request.paramPack.region_id); + + if ( + isNaN(feelingID) || + isNaN(languageID) || + isNaN(countryID) || + isNaN(platformID) || + isNaN(regionID) + ) { + response.sendStatus(403); + return; + } + + let community = await getCommunityByID(communityID); + if (!community) { + community = await Community.findOne({ + olive_community_id: communityID + }); + } + + if (!community) { + community = await getCommunityByTitleID(request.paramPack.title_id); + } + + if (!community || userSettings.account_status !== 0 || community.community_id === 'announcements') { + response.sendStatus(403); + return; + } + + let parentPost: HydratedPostDocument | null = null; + if (request.params.post_id) { + parentPost = await getPostByID(request.params.post_id.toString()); + + if (!parentPost) { + response.sendStatus(403); + return; + } + } + + // TODO - Clean this up + // * Nesting this because of how manu checks there are, extremely unreadable otherwise + if (!(community.admins && community.admins.indexOf(request.pid) !== -1 && userSettings.account_status === 0)) { + if (community.type >= 2) { + if (!(parentPost && community.allows_comments && community.open)) { + response.sendStatus(403); + return; + } + } + } + + let miiFace = 'normal_face.png'; + switch (parseInt(request.body.feeling_id)) { + case 1: + miiFace = 'smile_open_mouth.png'; + break; + case 2: + miiFace = 'wink_left.png'; + break; + case 3: + miiFace = 'surprise_open_mouth.png'; + break; + case 4: + miiFace = 'frustrated.png'; + break; + case 5: + miiFace = 'sorrow.png'; + break; + } + + if (messageBody) { + messageBody = messageBody.replace(/[^A-Za-z\d\s-_!@#$%^&*(){}‛¨ƒºª«»“”„¿¡←→↑↓√§¶†‡¦–—⇒⇔¤¢€£¥™©®+×÷=±∞ˇ˘˙¸˛˜′″µ°¹²³♭♪•…¬¯‰¼½¾♡♥●◆■▲▼☆★♀♂,./?;:'"\\<>]/g, ''); + } + + if (messageBody && messageBody.length > 280) { + messageBody = messageBody.substring(0, 280); + } + + if ((!messageBody || messageBody === '') && painting === '' && screenshot === '') { + response.status(400); + return; + } + + if (!Array.isArray(searchKey)) { + searchKey = [searchKey]; + } + + const document = { + id: '', // * This gets changed when saving the document for the first time + title_id: request.paramPack.title_id, + community_id: community.olive_community_id, + screen_name: userSettings.screen_name, + body: messageBody ? messageBody : '', + app_data: appData, + painting: painting, + screenshot: '', + screenshot_length: 0, + country_id: countryID, + created_at: new Date(), + feeling_id: feelingID, + search_key: searchKey, + topic_tag: topicTag, + is_autopost: (autopost) ? 1 : 0, + is_spoiler: (spoiler === '1') ? 1 : 0, + is_app_jumpable: (jumpable) ? 1 : 0, + language_id: languageID, + mii: user.mii.data, + mii_face_url: `https://mii.olv.pretendo.cc/mii/${user.pid}/${miiFace}`, + pid: request.pid, + platform_id: platformID, + region_id: regionID, + verified: (user.accessLevel === 2 || user.accessLevel === 3), + parent: parentPost ? parentPost.id : null, + removed: false + }; + + const duplicatePost = await getDuplicatePosts(request.pid, document); + + if (duplicatePost) { + response.status(400); + response.send(xmlbuilder.create({ + result: { + has_error: 1, + version: 1, + code: 400, + error_code: 7, + message: 'DUPLICATE_POST' + } + }).end({ pretty: true })); + return; + } + + const post = await Post.create(document); + + if (painting) { + const paintingBuffer = await processPainting(painting); + + if (paintingBuffer) { + await uploadCDNAsset('pn-cdn', `paintings/${request.pid}/${post.id}.png`, paintingBuffer, 'public-read'); + } else { + LOG_WARN(`PAINTING FOR POST ${post.id} FAILED TO PROCESS`); + } + } + + if (screenshot) { + const screenshotBuffer = Buffer.from(screenshot, 'base64'); + + await uploadCDNAsset('pn-cdn', `screenshots/${request.pid}/${post.id}.jpg`, screenshotBuffer, 'public-read'); + + post.screenshot = `/screenshots/${request.pid}/${post.id}.jpg`; + post.screenshot_length = screenshot.length; + + await post.save(); + } + + if (parentPost) { + parentPost.reply_count = (parentPost.reply_count || 0) + 1; + parentPost.save(); + } + + response.send(xmlbuilder.create({ + result: { + has_error: '0', + version: '1', + post: { + post: post.json({ with_mii: true }) + } + } + }).end({ pretty: true, allowEmpty: true })); +} + +export default router; \ No newline at end of file diff --git a/src/services/api/routes/status.ts b/src/services/api/routes/status.ts new file mode 100644 index 0000000..d77ec3a --- /dev/null +++ b/src/services/api/routes/status.ts @@ -0,0 +1,20 @@ +import express from 'express'; +import { getEndpoints } from '@/database'; + +const router = express.Router(); + +router.get('/', function(_request: express.Request, response: express.Response): void { + response.send('Pong!'); +}); + +router.get('/database', async function(_request: express.Request, response: express.Response): Promise { + const endpoints = await getEndpoints(); + + if (endpoints && endpoints.length <= 0) { + response.send('DB Connection Working! :D'); + } else { + response.send('DB Connection Not Working! D:'); + } +}); + +export default router; diff --git a/src/services/api/routes/topics.ts b/src/services/api/routes/topics.ts new file mode 100644 index 0000000..f559f21 --- /dev/null +++ b/src/services/api/routes/topics.ts @@ -0,0 +1,286 @@ +import express from 'express'; +import moment from 'moment'; +import xmlbuilder from 'xmlbuilder'; +import Cache from '@/cache'; +import { Post } from '@/models/post'; +import { Community } from '@/models/community'; +import { IPost } from '@/types/mongoose/post'; +import { HydratedCommunityDocument } from '@/types/mongoose/community'; +import { WWPResult, WWPTopic } from '@/types/miiverse/wara-wara-plaza'; + +const router = express.Router(); +const ONE_HOUR = 60 * 60 * 1000; +const WARA_WARA_PLAZA_CACHE = new Cache(ONE_HOUR); + +/* GET post titles. */ +router.get('/', async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + // * Commented out for now because we just don't + // * need this data here. WWP does not use the + // * current users data atm. Also some users have + // * BOSS tasks with outdated tokens, which aren't + // * usable and thus break this request. This is + // * done as a quick/hacky fix around that + // TODO - Re-enable this and filter out the current users posts + //let user: GetUserDataResponse; + // + //try { + // user = await getUserAccountData(request.pid); + //} catch (error) { + // // TODO - Log this error + // response.sendStatus(403); + // return; + //} + // + //let discovery: HydratedEndpointDocument | null; + // + //if (user) { + // discovery = await getEndpoint(user.serverAccessLevel); + //} else { + // discovery = await getEndpoint('prod'); + //} + // + //if (!discovery || !discovery.topics) { + // response.sendStatus(404); + // return; + //} + + if (!WARA_WARA_PLAZA_CACHE.valid()) { + const communities = await calculateMostPopularCommunities(24, 10); + + if (communities.length < 10) { + response.sendStatus(404); + return; + } + + WARA_WARA_PLAZA_CACHE.update(await generateTopicsData(communities)); + } + + const result = WARA_WARA_PLAZA_CACHE.get() || {}; + const xml = xmlbuilder.create({ + result: result + }, { + separateArrayItems: true + }).end({ + pretty: true, + allowEmpty: true + }); + + response.send(xml); +}); + +async function generateTopicsData(communities: HydratedCommunityDocument[]): Promise { + const topics: { + topic: WWPTopic; + }[] = []; + + const seenPeople: number[] = []; + + for (let i = 0; i < communities.length; i++) { + const community = communities[i]; + + const empathies = await Post.aggregate<{ _id: null; total: number; }>([ + { + $match: { + community_id: community.olive_community_id + } + }, + { + $group: { + _id: null, + total: { + $sum: '$empathy_count' + } + } + }, + { + $limit: 1 + } + ]); + + const topic: WWPTopic = { + empathy_count: empathies[0]?.total || 0, + has_shop_page: community.has_shop_page ? 1 : 0, + icon: community.icon, + title_ids: [], + title_id: community.title_id[0], + community_id: 0xFFFFFFFF, // * This is how it was in the real WWP. Unsure why, but it works + is_recommended: community.is_recommended ? 1 : 0, + name: community.name, + people: [], + position: i+1 + }; + + community.title_id.forEach(title_id => { + // * Just in case + if (title_id) { + topic.title_ids.push({ title_id }); + } + }); + + const people = await getCommunityPeople(community, seenPeople); + + for (const person of people) { + const post = Post.hydrate(person.post).json({ + with_mii: true, + topic_tag: true + }); + + post.community_id = 0xFFFFFFFF; // * Make this match above. This is how it was in the real WWP. Unsure why, but it works + + topic.people.push({ + person: { + posts: [ + { + post + } + ] + } + }); + + seenPeople.push(person._id); + } + + topics.push({ + topic: topic + }); + } + + return { + has_error: 0, + version: 1, + expire: moment().add(2, 'days').format('YYYY-MM-DD HH:MM:SS'), + request_name: 'topics', + topics + }; +} + +async function getCommunityPeople(community: HydratedCommunityDocument, seenPeople: number[], hours = 24): Promise<{ _id: number; post: IPost }[]> { + const now = new Date(); + const last24Hours = new Date(now.getTime() - hours * 60 * 60 * 1000); + const people = await Post.aggregate<{ _id: number; post: IPost }>([ + { + $match: { + title_id: { + $in: community.title_id + }, + created_at: { + $gte: last24Hours + }, + message_to_pid: null, + parent: null, + removed: false, + pid: { + // * Exclude people we have seen in other communities. + // * This increases generation time, but ensures the + // * max number of slots we can fill end up getting used + $nin: seenPeople + } + } + }, + { + $group: { + _id: '$pid', + post: { + $first: '$$ROOT' + } + } + }, + { + $limit: 70 // * Arbitrary + } + ]); + + // TODO - Remove this check once out of beta and have more users + // * We only do this because Juxtaposition is not super active + // * due to it being in beta. If we don't expand the search + // * time range then WWP still ends up fairly empty + // * + // * Ensure we have at *least* 20 people. Arbitrary. + // * If the year is less than 2020, assume we've gone + // * too far back. There are no more posts, just return + // * what was found + if (people.length < 20 && last24Hours.getFullYear() >= 2020) { + // * Double the search range each time to get + // * exponentially more posts. This speeds up + // * the search at the cost of using older posts + return getCommunityPeople(community, seenPeople, hours * 2); + } + + return people; +} + +async function calculateMostPopularCommunities(hours: number, limit: number): Promise { + const now = new Date(); + const last24Hours = new Date(now.getTime() - hours * 60 * 60 * 1000); + + if (!last24Hours) { + throw new Error('Invalid date'); + } + + const validCommunities = await Community.aggregate<{ _id: null; communities: string[]; }>([ + { + $match: { + type: 0, + parent: null + } + }, + { + $group: { + _id: null, + communities: { + $push: '$olive_community_id' + } + } + } + ]); + + const communityIDs = validCommunities[0].communities; + + if (!communityIDs) { + throw new Error('No communities found'); + } + + const popularCommunities = await Post.aggregate<{ _id: null; count: number; }>([ + { + $match: { + created_at: { + $gte: last24Hours + }, + message_to_pid: null, + community_id: { + $in: communityIDs + } + } + }, + { + $group: { + _id: '$community_id', + count: { + $sum: 1 + } + } + }, + { + $limit: limit + }, + { + $sort: { + count: -1 + } + } + ]); + + if (popularCommunities.length < limit) { + return calculateMostPopularCommunities(hours + hours, limit); + } + + return Community.find({ + olive_community_id: { + $in: popularCommunities.map(({ _id }) => _id) + } + }); +} + +export default router; diff --git a/src/services/api/routes/users.ts b/src/services/api/routes/users.ts new file mode 100644 index 0000000..912cc99 --- /dev/null +++ b/src/services/api/routes/users.ts @@ -0,0 +1,26 @@ +import express from 'express'; +import xmlbuilder from 'xmlbuilder'; +import { getValueFromQueryString } from '@/util'; + +const router = express.Router(); + +router.get('/:pid/notifications', function(request: express.Request, response: express.Response): void { + const type = getValueFromQueryString(request.query, 'type')[0]; + const titleID = getValueFromQueryString(request.query, 'title_id')[0]; + const pid = getValueFromQueryString(request.query, 'pid')[0]; + + console.log(type); + console.log(titleID); + console.log(pid); + + response.type('application/xml'); + response.send(xmlbuilder.create({ + result: { + has_error: 0, + version: 1, + posts: ' ' + } + }).end({ pretty: true })); +}); + +export default router; diff --git a/src/services/discovery/index.ts b/src/services/discovery/index.ts new file mode 100644 index 0000000..95f3d56 --- /dev/null +++ b/src/services/discovery/index.ts @@ -0,0 +1,22 @@ +import express from 'express'; +import subdomain from 'express-subdomain'; +import { LOG_INFO } from '@/logger'; + +import discoveryHandlers from '@/services/discovery/routes/discovery'; + +// Main router for endpointsindex.js +const router = express.Router(); + +// Router to handle the subdomain restriction +const discovery = express.Router(); + +// Create subdomains +LOG_INFO('[MIIVERSE] Creating \'discovery\' subdomain'); +router.use(subdomain('discovery.olv', discovery)); +router.use(subdomain('discovery-test.olv', discovery)); +router.use(subdomain('discovery-dev.olv', discovery)); + +// Setup routes +discovery.use('/v1/endpoint', discoveryHandlers); + +export default router; \ No newline at end of file diff --git a/src/services/discovery/routes/discovery.ts b/src/services/discovery/routes/discovery.ts new file mode 100644 index 0000000..15e4b5a --- /dev/null +++ b/src/services/discovery/routes/discovery.ts @@ -0,0 +1,104 @@ +import express from 'express'; +import xmlbuilder from 'xmlbuilder'; +import { GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc'; +import { getUserAccountData } from '@/util'; +import { getEndpoint } from '@/database'; +import { HydratedEndpointDocument } from '@/types/mongoose/endpoint'; + +const router = express.Router(); + +/* GET discovery server. */ +router.get('/', async function (request: express.Request, response: express.Response): Promise { + response.type('application/xml'); + + let user: GetUserDataResponse; + + try { + user = await getUserAccountData(request.pid); + } catch (error) { + // TODO - Log this error + response.sendStatus(404); + return; + } + + let discovery: HydratedEndpointDocument | null; + + if (user) { + discovery = await getEndpoint(user.serverAccessLevel); + } else { + discovery = await getEndpoint('prod'); + } + + // TODO - Better error + if (!discovery) { + response.sendStatus(404); + return; + } + + let message = ''; + let errorCode = 0; + switch (discovery.status) { + case 0: + response.send(xmlbuilder.create({ + result: { + has_error: 0, + version: 1, + endpoint: { + host: discovery.host, + api_host: discovery.api_host, + portal_host: discovery.portal_host, + n3ds_host: discovery.n3ds_host + } + } + }).end({ pretty: true })); + + return ; + case 1: + message = 'SYSTEM_UPDATE_REQUIRED'; + errorCode = 1; + break; + case 2: + message = 'SETUP_NOT_COMPLETE'; + errorCode = 2; + break; + case 3: + message = 'SERVICE_MAINTENANCE'; + errorCode = 3; + break; + case 4: + message = 'SERVICE_CLOSED'; + errorCode = 4; + break; + case 5: + message = 'PARENTAL_CONTROLS_ENABLED'; + errorCode = 5; + break; + case 6: + message = 'POSTING_LIMITED_PARENTAL_CONTROLS'; + errorCode = 6; + break; + case 7: + message = 'NNID_BANNED'; + errorCode = 7; + response.type('application/xml'); + break; + default: + message = 'SERVER_ERROR'; + errorCode = 15; + response.type('application/xml'); + break; + } + + response.status(400); + response.send(xmlbuilder.create({ + result: { + has_error: 1, + version: 1, + code: 400, + error_code: errorCode, + message: message + } + }).end({ pretty: true })); +}); + +export default router; diff --git a/src/services/miiverse-api/index.js b/src/services/miiverse-api/index.js deleted file mode 100644 index 03b6436..0000000 --- a/src/services/miiverse-api/index.js +++ /dev/null @@ -1,34 +0,0 @@ -const express = require('express'); -const subdomain = require('express-subdomain'); -const sessionMiddleware = require('../../middleware/session'); -const pnidMiddleware = require('../../middleware/pnid'); -const logger = require('../../logger'); -const routes = require('./routes'); - -// Main router for endpointsindex.js -const router = express.Router(); - -// Router to handle the subdomain restriction -const discovery = express.Router(); -const api = express.Router(); - -// Create subdomains -logger.info('[MIIVERSE] Creating \'discovery\' subdomain'); -router.use(subdomain('discovery.olv', discovery)); -logger.info('[MIIVERSE] Creating \'api\' subdomain'); -router.use(subdomain('api.olv', api)); - - -logger.info('[MIIVERSE] Importing middleware'); -discovery.use(sessionMiddleware); -discovery.use(pnidMiddleware); - -// Setup routes -discovery.use('/v1/endpoint', routes.DISCOVERY); -api.use('/v1/posts', routes.POST); -api.use('/v1/friend_messages', routes.MESSAGE); -api.use('/v1/communities/', routes.COMMUNITY); -api.use('/v1/people/', routes.PEOPLE); -api.use('/v1/topics/', routes.TOPICS); - -module.exports = router; diff --git a/src/services/miiverse-api/routes/communities.js b/src/services/miiverse-api/routes/communities.js deleted file mode 100644 index fd32bf2..0000000 --- a/src/services/miiverse-api/routes/communities.js +++ /dev/null @@ -1,70 +0,0 @@ -var express = require('express'); -var router = express.Router(); -const database = require('../../../database'); -const comPostGen = require('../../../util/CommunityPostGen'); -const processHeaders = require('../../../util/util'); - -/* GET post titles. */ -router.get('/', async function (req, res) { - const paramPack = processHeaders.data.decodeParamPack(req.headers["x-nintendo-parampack"]); - let community = await database.getCommunityByTitleID(paramPack.title_id); - if (community != null) { - let response = await comPostGen.Communities(community); - res.contentType("application/xml"); - res.send(response); - } else { - res.status(404); - res.send(); - } -}); - -router.get('/popular', async function (req, res) { - let community = await database.getMostPopularCommunities(100); - if (community != null) { - res.contentType("application/json"); - res.send(community); - } else { - res.status(404); - res.send(); - } -}); - -router.get('/new', async function (req, res) { - let community = await database.getNewCommunities(100); - if (community != null) { - res.contentType("application/json"); - res.send(community); - } else { - res.status(404); - res.send(); - } -}); - -router.get('/0/posts', async function (req, res) { - const paramPack = processHeaders.data.decodeParamPack(req.headers["x-nintendo-parampack"]); - let community = await database.getCommunityByTitleID(paramPack.title_id); - if(community != null) - { - let posts; - if(req.query.search_key) - posts = await database.getPostsByCommunityKey(community, parseInt(req.query.limit), req.query.search_key); - else - posts = await database.getPostsByCommunity(community, parseInt(req.query.limit)); - - /* Build formatted response and send it off. */ - let response; - if(req.query.with_mii === 1) - response = await comPostGen.PostsResponseWithMii(posts, community); - else - response = await comPostGen.PostsResponse(posts, community); - res.contentType("application/xml"); - res.send(response); - } - else - { - res.status(404); - res.send(); - } -}); - -module.exports = router; diff --git a/src/services/miiverse-api/routes/discovery.js b/src/services/miiverse-api/routes/discovery.js deleted file mode 100644 index 2baf30e..0000000 --- a/src/services/miiverse-api/routes/discovery.js +++ /dev/null @@ -1,198 +0,0 @@ -var express = require('express'); -var xml = require('object-to-xml'); -const database = require('../../../database'); -const util = require('../../../util/util'); -var router = express.Router(); - -/* GET discovery server. */ -router.get('/', async function (req, res) { - const discovery = await database.getDiscoveryHosts(); - try - { - let pid = util.data.processServiceToken(req.headers["x-nintendo-servicetoken"]); - let usrObj; - if(pid == null) - { - throw new Error('The User token was not valid'); - } - else - { - usrObj = await util.data.processUser(pid); - if(!usrObj) { - res.set("Content-Type", "application/xml"); - res.statusCode = 400; - response = { - result: { - has_error: 1, - version: 1, - code: 400, - error_code: 2, - message: "SETUP_NOT_COMPLETE" - } - }; - return res.send("\n" + xml(response)); - } - switch (usrObj.account_status) { - case 0: - break; - case 1: - case 2: - case 3: - res.set("Content-Type", "application/xml"); - res.statusCode = 400; - response = { - result: { - has_error: 1, - version: 1, - code: 400, - error_code: 7, - message: "POSTING_FROM_NNID" - } - }; - res.send("\n" + xml(response)); - } - } - - } - catch (e) - { - console.error(e); - } - switch(discovery.has_error) - { - case 0 : - res.set("Content-Type", "application/xml"); - response = { - result: { - has_error: 0, - version: discovery.version, - endpoint: { - host: discovery.endpoint.host, - api_host: discovery.endpoint.api_host, - portal_host: discovery.endpoint.portal_host, - n3ds_host: discovery.endpoint.n3ds_host - } - } - }; - res.send("\n" + xml(response)); - break; - case 1 : - res.set("Content-Type", "application/xml"); - res.statusCode = 400; - response = { - result: { - has_error: 1, - version: 1, - code: 400, - error_code: 1, - message: "SYSTEM_UPDATE_REQUIRED" - } - }; - res.send("\n" + xml(response)); - break; - case 2 : - res.set("Content-Type", "application/xml"); - res.statusCode = 400; - response = { - result: { - has_error: 1, - version: 1, - code: 400, - error_code: 2, - message: "SETUP_NOT_COMPLETE" - } - }; - res.send("\n" + xml(response)); - break; - case 3 : - res.set("Content-Type", "application/xml"); - res.statusCode = 400; - response = { - result: { - has_error: 1, - version: 1, - code: 400, - error_code: 3, - message: "SERVICE_MAINTENANCE" - } - }; - res.send("\n" + xml(response)); - break; - case 4: - res.set("Content-Type", "application/xml"); - res.statusCode = 400; - response = { - result: { - has_error: 1, - version: 1, - code: 400, - error_code: 4, - message: "SERVICE_CLOSED" - } - }; - res.send("\n" + xml(response)); - break; - case 5 : - res.set("Content-Type", "application/xml"); - res.statusCode = 400; - response = { - result: { - has_error: 1, - version: 1, - code: 400, - error_code: 5, - message: "PARENTAL_CONTROLS_ENABLED" - } - }; - res.send("\n" + xml(response)); - break; - case 6 : - res.set("Content-Type", "application/xml"); - res.statusCode = 400; - response = { - result: { - has_error: 1, - version: 1, - code: 400, - error_code: 6, - message: "POSTING_LIMITED_PARENTAL_CONTROLS" - } - }; - res.send("\n" + xml(response)); - break; - case 7 : - res.set("Content-Type", "application/xml"); - res.statusCode = 400; - response = { - result: { - has_error: 1, - version: 1, - code: 400, - error_code: 7, - message: "PNID_BANNED" - } - }; - res.send("\n" + xml(response)); - break; - default : - res.set("Content-Type", "application/xml"); - res.statusCode = 400; - response = { - result: { - has_error: 1, - version: 1, - code: 400, - error_code: 15, - message: "SERVER_ERROR" - } - }; - res.send("\n" + xml(response)); - break; - } -}); - -router.post('/posts', function (req, res) { - res.sendStatus(200); -}); - -module.exports = router; diff --git a/src/services/miiverse-api/routes/index.js b/src/services/miiverse-api/routes/index.js deleted file mode 100644 index 25c4075..0000000 --- a/src/services/miiverse-api/routes/index.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - DISCOVERY: require('./discovery'), - POST: require('./post'), - MESSAGE: require('./message'), - COMMUNITY: require('./communities'), - PEOPLE: require('./people'), - TOPICS: require('./topics') -}; diff --git a/src/services/miiverse-api/routes/message.js b/src/services/miiverse-api/routes/message.js deleted file mode 100644 index 0f062ff..0000000 --- a/src/services/miiverse-api/routes/message.js +++ /dev/null @@ -1,174 +0,0 @@ -var express = require('express'); -var router = express.Router(); -const moment = require('moment'); -var xml = require('object-to-xml'); -const { POST } = require('../../../models/post'); -const { CONVERSATION } = require('../../../models/conversation'); -const util = require('../../../util/util'); -const database = require('../../../database'); -var multer = require('multer'); -const snowflake = require('node-snowflake').Snowflake; -var upload = multer(); - -/* GET post titles. */ -router.post('/', upload.none(), async function (req, res, next) { - try - { - let paramPackData = util.data.decodeParamPack(req.headers["x-nintendo-parampack"]); - let pid = util.data.processServiceToken(req.headers["x-nintendo-servicetoken"]); - if(pid === null) - { - throw new Error('The User token was not valid'); - } - else - { - let conversation = await database.getConversation(pid.toString(), req.body.message_to_pid.toString()) - if(!conversation) { - let user = await database.getUserByPID(pid); - let user2 = await database.getUserByPID(req.body.message_to_pid); - if(!user || !user2) - return res.sendStatus(422) - let doc = { - message_preview: req.body.body, - pids: [ - { - pid: user.pid.toString(), - official: user.official, - screen_name: user.user_id, - read: true - }, - { - pid: user2.pid.toString(), - official: user2.official, - screen_name: user2.user_id, - read: false - } - ] - } - const newConversation = new CONVERSATION(doc); - await newConversation.save(); - } - else { - let messageType = ''; - if(req.body.screenshot) - messageType = '(Screenshot)'; - else if(req.body.painting) - messageType = '(Drawing)'; - else - messageType = req.body.body; - await conversation.newMessage(messageType, req.pid.toString()) - } - conversation = await database.getConversation(pid.toString(), req.body.message_to_pid.toString()) - let user = await util.data.processUser(pid); - let appData = ""; - if (req.body.app_data) { - appData = req.body.app_data.replace(/\0/g, "").trim(); - } - let painting = ""; - if (req.body.painting) { - painting = req.body.painting.replace(/\0/g, "").trim(); - } - let paintingURI = ""; - if (req.body.painting) { - paintingURI = await util.data.processPainting(painting); - } - let screenshot = ""; - if (req.body.screenshot) { - screenshot = req.body.screenshot.replace(/\0/g, "").trim(); - } - - let miiFace; - console.log(parseInt(req.body.feeling_id)) - switch (parseInt(req.body.feeling_id)) { - case 1: - miiFace = 'smile_open_mouth.png'; - break; - case 2: - miiFace = 'wink_left.png'; - break; - case 3: - miiFace = 'surprise_open_mouth.png'; - break; - case 4: - miiFace = 'frustrated.png'; - break; - case 5: - miiFace = 'sorrow.png'; - break; - default: - miiFace = 'normal_face.png'; - break; - } - - const document = { - title_id: paramPackData.title_id, - screen_name: user.user_id, - body: req.body.body, - app_data: appData, - painting: painting, - painting_uri: paintingURI, - screenshot: screenshot, - url: req.body.url, - search_key: req.body.search_key, - topic_tag: req.body.topic_tag, - country_id: paramPackData.country_id, - created_at: new Date(), - feeling_id: req.body.feeling_id, - id: snowflake.nextId(), - is_autopost: req.body.is_autopost, - is_spoiler: req.body.is_spoiler, - is_app_jumpable: req.body.is_app_jumpable, - language_id: req.body.language_id, - mii: user.mii, - mii_face_url: `http://mii.olv.pretendo.cc/mii/${user.pid}/${miiFace}`, - pid: user.pid, - verified: user.official, - platform_id: paramPackData.platform_id, - region_id: paramPackData.region_id, - parent: null, - message_to_pid: req.body.message_to_pid, - conversation_id: conversation.id - }; - const newPost = new POST(document); - newPost.save(); - res.sendStatus(200); - } - } - catch (e) - { - console.error(e); - res.set("Content-Type", "application/xml"); - res.statusCode = 400; - response = { - result: { - has_error: 1, - version: 1, - code: 400, - error_code: 7, - message: "POSTING_FROM_NNID" - } - }; - res.send("\n" + xml(response)); - } - -}); - -router.post('/:post_id/empathies', upload.none(), async function (req, res, next) { - let pid = util.data.processServiceToken(req.headers["x-nintendo-servicetoken"]); - const post = await database.getPostByID(req.params.post_id); - if(pid === null) { - res.sendStatus(403); - return; - } - let user = await database.getUserByPID(pid); - if(user.likes.indexOf(post.id) === -1 && user.id !== post.pid) - { - post.upEmpathy(); - user.addToLikes(post.id) - res.sendStatus(200); - } - else - res.sendStatus(403); -}); - -module.exports = router; diff --git a/src/services/miiverse-api/routes/people.js b/src/services/miiverse-api/routes/people.js deleted file mode 100644 index e66dc4d..0000000 --- a/src/services/miiverse-api/routes/people.js +++ /dev/null @@ -1,34 +0,0 @@ -var express = require('express'); -var router = express.Router(); -const database = require('../../../database'); -const pplPostGen = require('../../../util/peoplePostGen'); -const processHeaders = require('../../../util/util'); - -/* GET post titles. */ -router.get('/', async function (req, res) { - let community = await database.getCommunityByTitleID(1407375153321472); - if(community != null) - { - let posts; - if(req.query.search_key) - posts = await database.getPostsByCommunityKey(community, parseInt(req.query.limit), req.query.search_key); - else - posts = await database.getPostsByCommunity(community, parseInt(req.query.limit)); - - /* Build formatted response and send it off. */ - let response; - if(req.query.with_mii === 1) - response = await pplPostGen.PostsResponseWithMii(posts, community); - else - response = await pplPostGen.PostsResponse(posts, community); - res.contentType("application/xml"); - res.send(response); - } - else - { - res.status(404); - res.send(); - } -}); - -module.exports = router; diff --git a/src/services/miiverse-api/routes/post.js b/src/services/miiverse-api/routes/post.js deleted file mode 100644 index 65c8a04..0000000 --- a/src/services/miiverse-api/routes/post.js +++ /dev/null @@ -1,137 +0,0 @@ -var express = require('express'); -var router = express.Router(); -const moment = require('moment'); -var xml = require('object-to-xml'); -const { POST } = require('../../../models/post'); -const util = require('../../../util/util'); -const database = require('../../../database'); -var multer = require('multer'); -const snowflake = require('node-snowflake').Snowflake; -var upload = multer(); - -/* GET post titles. */ -router.post('/', upload.none(), async function (req, res, next) { - try - { - let paramPackData = util.data.decodeParamPack(req.headers["x-nintendo-parampack"]); - let pid = util.data.processServiceToken(req.headers["x-nintendo-servicetoken"]); - if(pid === null) - { - throw new Error('The User token was not valid'); - } - else - { - let user = await util.data.processUser(pid); - let community = await database.getCommunityByTitleID(paramPackData.title_id) - if(community.community_id === 'announcements') - return res.sendStatus(403) - let appData = ""; - if (req.body.app_data) { - appData = req.body.app_data.replace(/\0/g, "").replace(/\r?\n|\r/g, "").trim(); - } - let painting = ""; - if (req.body.painting) { - painting = req.body.painting.replace(/\0/g, "").replace(/\r?\n|\r/g, "").trim(); - } - let paintingURI = ""; - if (req.body.painting) { - paintingURI = await util.data.processPainting(painting); - } - let screenshot = ""; - if (req.body.screenshot) { - screenshot = req.body.screenshot.replace(/\0/g, "").trim(); - } - - let miiFace; - console.log(parseInt(req.body.feeling_id)) - switch (parseInt(req.body.feeling_id)) { - case 1: - miiFace = 'smile_open_mouth.png'; - break; - case 2: - miiFace = 'wink_left.png'; - break; - case 3: - miiFace = 'surprise_open_mouth.png'; - break; - case 4: - miiFace = 'frustrated.png'; - break; - case 5: - miiFace = 'sorrow.png'; - break; - default: - miiFace = 'normal_face.png'; - break; - } - - const document = { - title_id: paramPackData.title_id, - screen_name: user.user_id, - body: req.body.body, - app_data: appData, - painting: painting, - painting_uri: paintingURI, - screenshot: screenshot, - url: req.body.url, - search_key: req.body.search_key, - topic_tag: req.body.topic_tag, - community_id: community.community_id, - country_id: paramPackData.country_id, - created_at: new Date(), - feeling_id: req.body.feeling_id, - id: snowflake.nextId(), - is_autopost: req.body.is_autopost, - is_spoiler: req.body.is_spoiler, - is_app_jumpable: req.body.is_app_jumpable, - language_id: req.body.language_id, - mii: user.mii, - mii_face_url: `http://mii.olv.pretendo.cc/mii/${user.pid}/${miiFace}`, - pid: user.pid, - verified: user.official, - platform_id: paramPackData.platform_id, - region_id: paramPackData.region_id, - parent: null, - }; - const newPost = new POST(document); - newPost.save(); - res.sendStatus(200); - } - } - catch (e) - { - console.error(e); - res.set("Content-Type", "application/xml"); - res.statusCode = 400; - response = { - result: { - has_error: 1, - version: 1, - code: 400, - error_code: 7, - message: "POSTING_FROM_NNID" - } - }; - res.send("\n" + xml(response)); - } -}); - -router.post('/:post_id/empathies', upload.none(), async function (req, res, next) { - let pid = util.data.processServiceToken(req.headers["x-nintendo-servicetoken"]); - const post = await database.getPostByID(req.params.post_id); - if(pid === null) { - res.sendStatus(403); - return; - } - let user = await database.getUserByPID(pid); - if(user.likes.indexOf(post.id) === -1 && user.id !== post.pid) - { - post.upEmpathy(); - user.addToLikes(post.id) - res.sendStatus(200); - } - else - res.sendStatus(403); -}); - -module.exports = router; diff --git a/src/services/miiverse-api/routes/topics.js b/src/services/miiverse-api/routes/topics.js deleted file mode 100644 index 2db8f6f..0000000 --- a/src/services/miiverse-api/routes/topics.js +++ /dev/null @@ -1,19 +0,0 @@ -var express = require('express'); -var router = express.Router(); -const database = require('../../../database'); -const comPostGen = require('../../../util/CommunityPostGen'); -const processHeaders = require('../../../util/util'); -const xmlbuilder = require("xmlbuilder"); -const moment = require("moment"); - -/* GET post titles. */ -router.get('/', async function (req, res) { - let communities = await database.getCommunities(10); - if(communities === null) - return res.sendStatus(404); - let response = await comPostGen.topics(communities); - res.contentType("application/xml"); - res.send(response); -}); - -module.exports = router; diff --git a/src/types/common/config.ts b/src/types/common/config.ts new file mode 100644 index 0000000..130e192 --- /dev/null +++ b/src/types/common/config.ts @@ -0,0 +1,30 @@ +import mongoose from 'mongoose'; + +export interface Config { + http: { + port: number; + }; + account_server_address: string; + mongoose: { + connection_string: string; + options: mongoose.ConnectOptions; + }; + s3: { + endpoint: string; + key: string; + secret: string; + }; + grpc: { + friends: { + ip: string; + port: number; + api_key: string; + }; + account: { + ip: string; + port: number; + api_key: string; + }; + }; + aes_key: string; +} \ No newline at end of file diff --git a/src/types/common/formatted-message.ts b/src/types/common/formatted-message.ts new file mode 100644 index 0000000..2871234 --- /dev/null +++ b/src/types/common/formatted-message.ts @@ -0,0 +1,28 @@ +export interface FormattedMessage { + post: { + body: string; + country_id: number; + created_at: string; + feeling_id: number; + id: string; + is_autopost: number; + is_spoiler: number; + is_app_jumpable: number; + empathy_added?: number; // * Only optional because they are optional in Posts + language_id: number; + message_to_pid?: string; // * Only optional because they are optional in Posts + mii: string; + mii_face_url: string; + number: number; + pid: number; + platform_id: number; + region_id: number; + reply_count?: number; // * Only optional because they are optional in Posts + screen_name: string; + topic_tag: { + name: string; + title_id: number + }; + title_id: string; + }; +} \ No newline at end of file diff --git a/src/types/common/param-pack.ts b/src/types/common/param-pack.ts new file mode 100644 index 0000000..7bb252b --- /dev/null +++ b/src/types/common/param-pack.ts @@ -0,0 +1,16 @@ +export interface ParamPack { + title_id: string; + access_key: string; + platform_id: string; + region_id: string; + language_id: string; + country_id: string; + area_id: string; + network_restriction: string; + friend_restriction: string; + rating_restriction: string; + rating_organization: string; + transferable_id: string; + tz_name: string; + utc_offset: string; +} \ No newline at end of file diff --git a/src/types/common/token.ts b/src/types/common/token.ts new file mode 100644 index 0000000..e414ba3 --- /dev/null +++ b/src/types/common/token.ts @@ -0,0 +1,8 @@ +export interface Token { + system_type: number; + token_type: number; + pid: number; + access_level: number; + title_id: bigint; + expire_time: bigint; +} \ No newline at end of file diff --git a/src/types/express-subdomain.d.ts b/src/types/express-subdomain.d.ts new file mode 100644 index 0000000..b4ae490 --- /dev/null +++ b/src/types/express-subdomain.d.ts @@ -0,0 +1,16 @@ +// * Credit to https://github.com/bmullan91/express-subdomain/pull/61 for the types! + +declare module 'express-subdomain'{ + import type { Request, Response, Router } from 'express'; + + /** + * @description The subdomain function. + * @param subdomain The subdomain to listen on. + * @param fn The listener function, takes a response and request. + * @returns A function call to the value passed as FN, or void (the next function). + */ + export default function subdomain( + subdomain: string, + fn: Router + ): (req: Request, res: Response, next: () => void) => void | typeof fn; +} \ No newline at end of file diff --git a/src/types/express.d.ts b/src/types/express.d.ts new file mode 100644 index 0000000..1a214ee --- /dev/null +++ b/src/types/express.d.ts @@ -0,0 +1,10 @@ +import { ParamPack } from '@/types/common/param-pack'; + +declare global { + namespace Express { + interface Request { + pid: number; + paramPack: ParamPack + } + } +} \ No newline at end of file diff --git a/src/types/miiverse/community.ts b/src/types/miiverse/community.ts new file mode 100644 index 0000000..2048f79 --- /dev/null +++ b/src/types/miiverse/community.ts @@ -0,0 +1,33 @@ +import { PostData } from '@/types/miiverse/post'; + +export type CommunityData = { + community_id: string; + name: string; + description: string; + icon: string; + icon_3ds: string; + pid: number; + app_data: string; + is_user_community: string; +}; + +export type CommunitiesResult = { + has_error: 0 | 1; + version: 1; + request_name: 'communities'; + communities: { + community: CommunityData; + }[]; +}; + +export type CommunityPostsResult = { + has_error: 0 | 1; + version: 1; + request_name: 'posts'; + topic: { + community_id: string; + }; + posts: { + post: PostData; + }[]; +}; \ No newline at end of file diff --git a/src/types/miiverse/people.ts b/src/types/miiverse/people.ts new file mode 100644 index 0000000..500689d --- /dev/null +++ b/src/types/miiverse/people.ts @@ -0,0 +1,27 @@ +import { PostData } from '@/types/miiverse/post'; +import { SettingsData } from '@/types/miiverse/settings'; + +export type PersonPosts = { + person: { + posts: { + post: PostData; + }[]; + } +}; + +export type PeoplePostsResult = { + has_error: 0 | 1; + version: 1; + expire: string; + request_name: 'posts'; + people: PersonPosts[]; +}; + +export type PeopleFollowingResult = { + has_error: 0 | 1; + version: 1; + request_name: 'user_infos'; + people: { + person: SettingsData; + }[]; +}; \ No newline at end of file diff --git a/src/types/miiverse/post.ts b/src/types/miiverse/post.ts new file mode 100644 index 0000000..378cb61 --- /dev/null +++ b/src/types/miiverse/post.ts @@ -0,0 +1,53 @@ +export type PostData = { + app_data?: string; // TODO - I try to keep these fields in the real order they show up in, but idk where this one goes + body?: string; + community_id: number | string; // TODO - Remove this union. Only done to bypass some errors which don't break anything + country_id: number; + created_at: string; + feeling_id: number; + id: string; + is_autopost: 0 | 1; + is_community_private_autopost: 0 | 1; + is_spoiler: 0 | 1; + is_app_jumpable: 0 | 1; + empathy_count: number; + language_id: number; + mii?: string; + mii_face_url?: string; + number: number; + painting?: PostPainting; + pid: number; + platform_id: number; + region_id: number; + reply_count: number; + screen_name: string; + screenshot?: PostScreenshot; + topic_tag?: PostTopicTag; + title_id: string; +}; + +export type PostPainting = { + format: string; + content: string; + size: number; + url: string; +}; + +export type PostScreenshot = { + size: number; + url: string; +}; + +export type PostTopicTag = { + name: string; + title_id: string; +}; + +export type PostRepliesResult = { + has_error: 0 | 1; + version: 1; + request_name: 'replies'; + posts: { + post: PostData; + }[]; +}; \ No newline at end of file diff --git a/src/types/miiverse/settings.ts b/src/types/miiverse/settings.ts new file mode 100644 index 0000000..ae43819 --- /dev/null +++ b/src/types/miiverse/settings.ts @@ -0,0 +1,4 @@ +export type SettingsData = { + pid: number; + screen_name: string; +}; \ No newline at end of file diff --git a/src/types/miiverse/wara-wara-plaza.ts b/src/types/miiverse/wara-wara-plaza.ts new file mode 100644 index 0000000..582e9a0 --- /dev/null +++ b/src/types/miiverse/wara-wara-plaza.ts @@ -0,0 +1,27 @@ +import { PersonPosts } from '@/types/miiverse/people'; + +export type WWPTopic = { + empathy_count: number; + has_shop_page: 0 | 1; + icon: string; + title_ids: { + title_id: string; + }[]; + title_id: string; + community_id: number; + is_recommended: 0 | 1; + name: string; + people: PersonPosts[]; + position: number; +}; + +export type WWPResult = { + has_error: 0 | 1; + version: 1; + expire: string; + request_name: 'topics'; + topics: { + topic: WWPTopic; + }[]; +}; + diff --git a/src/types/mongoose/community-posts-query.ts b/src/types/mongoose/community-posts-query.ts new file mode 100644 index 0000000..eac6a11 --- /dev/null +++ b/src/types/mongoose/community-posts-query.ts @@ -0,0 +1,24 @@ +// TODO - Make this more generic + +export interface CommunityPostsQuery { + community_id?: string; + removed: boolean; + app_data?: { + $ne?: null; + $eq?: null; + }; + message_to_pid?: { + $eq: null; + }; + search_key?: string; + is_spoiler?: 0 | 1; + painting?: { + $ne: null; + }; + pid?: number | number[] | { + $in: number[]; + }; + parent?: { + $eq: null + }; +} \ No newline at end of file diff --git a/src/types/mongoose/community.ts b/src/types/mongoose/community.ts new file mode 100644 index 0000000..03f066c --- /dev/null +++ b/src/types/mongoose/community.ts @@ -0,0 +1,43 @@ +import { Model, Types, HydratedDocument } from 'mongoose'; +import { CommunityData } from '@/types/miiverse/community'; + +enum COMMUNITY_TYPE { + Main = 0, + Sub = 1, + Announcement = 2, + Private = 3 +} + +export interface ICommunity { + platform_id: number; + name: string; + description: string; + open: boolean; + allows_comments: boolean; + type: COMMUNITY_TYPE; + parent: string; + admins: Types.Array; + owner: number; + created_at: Date; + empathy_count: number; + followers: number; + has_shop_page: number; + icon: string; + title_ids: Types.Array; + title_id: Types.Array; + community_id: string; + olive_community_id: string; + is_recommended: number; + app_data: string; + user_favorites: Types.Array; +} + +export interface ICommunityMethods { + addUserFavorite(pid: number): Promise; + delUserFavorite(pid: number): Promise; + json(): CommunityData; +} + +export type CommunityModel = Model; + +export type HydratedCommunityDocument = HydratedDocument; \ No newline at end of file diff --git a/src/types/mongoose/content.ts b/src/types/mongoose/content.ts new file mode 100644 index 0000000..6934632 --- /dev/null +++ b/src/types/mongoose/content.ts @@ -0,0 +1,12 @@ +import { Model, Types, HydratedDocument } from 'mongoose'; + +export interface IContent { + pid: number; + followed_communities: Types.Array; + followed_users: Types.Array; + following_users: Types.Array; +} + +export type ContentModel = Model; + +export type HydratedContentDocument = HydratedDocument; \ No newline at end of file diff --git a/src/types/mongoose/conversation.ts b/src/types/mongoose/conversation.ts new file mode 100644 index 0000000..7f73c7b --- /dev/null +++ b/src/types/mongoose/conversation.ts @@ -0,0 +1,23 @@ +import { Model, Types, HydratedDocument } from 'mongoose'; + +export type ConversationUser = { + pid: number; + official: boolean; + read: boolean; +}; + +export interface IConversation { + id: string; + created_at: Date; + last_updated: Date; + message_preview: string, + users: Types.Array; +} + +export interface IConversationMethods { + newMessage(message: string, senderPID: number): Promise; +} + +export type ConversationModel = Model; + +export type HydratedConversationDocument = HydratedDocument; \ No newline at end of file diff --git a/src/types/mongoose/endpoint.ts b/src/types/mongoose/endpoint.ts new file mode 100644 index 0000000..281bf93 --- /dev/null +++ b/src/types/mongoose/endpoint.ts @@ -0,0 +1,16 @@ +import { Model, HydratedDocument } from 'mongoose'; + +export interface IEndpoint { + status: number; + server_access_level: string; + topics: boolean; + guest_access: boolean; + host: string; + api_host: string; + portal_host: string; + n3ds_host: string; +} + +export type EndpointModel = Model; + +export type HydratedEndpointDocument = HydratedDocument; \ No newline at end of file diff --git a/src/types/mongoose/notification.ts b/src/types/mongoose/notification.ts new file mode 100644 index 0000000..7ecf24c --- /dev/null +++ b/src/types/mongoose/notification.ts @@ -0,0 +1,20 @@ +import { Model, Types, HydratedDocument } from 'mongoose'; + +export type NotificationUser = { + user: string; + timestamp: number; +} + +export interface INotification { + pid: string; + type: string; + link: string; + objectID: string; + users: Types.Array; + read: boolean; + lastUpdated: number; +} + +export type NotificationModel = Model; + +export type HydratedNotificationDocument = HydratedDocument; \ No newline at end of file diff --git a/src/types/mongoose/post-to-json-options.ts b/src/types/mongoose/post-to-json-options.ts new file mode 100644 index 0000000..dc11f9f --- /dev/null +++ b/src/types/mongoose/post-to-json-options.ts @@ -0,0 +1,5 @@ +export interface PostToJSONOptions { + with_mii: boolean; + app_data?: boolean; + topic_tag?: boolean; +} \ No newline at end of file diff --git a/src/types/mongoose/post.ts b/src/types/mongoose/post.ts new file mode 100644 index 0000000..6e90b78 --- /dev/null +++ b/src/types/mongoose/post.ts @@ -0,0 +1,57 @@ +import { Model, Types, HydratedDocument } from 'mongoose'; +import { HydratedCommunityDocument } from '@/types/mongoose/community'; +import { PostToJSONOptions } from '@/types/mongoose/post-to-json-options'; +import { PostData, PostPainting, PostScreenshot, PostTopicTag } from '@/types/miiverse/post'; + +export interface IPost { + id: string; + title_id: string; + screen_name: string; + body: string; + app_data: string; + painting: string; + screenshot: string; + screenshot_length: number; + search_key: string[]; + topic_tag: string; + community_id: string; + created_at: Date; + feeling_id: number; + is_autopost: number; + is_community_private_autopost?: number; + is_spoiler: number; + is_app_jumpable: number; + empathy_count?: number; + country_id: number; + language_id: number; + mii: string; + mii_face_url: string; + pid: number; + platform_id: number; + region_id: number; + parent: string; + reply_count?: number; + verified: boolean; + message_to_pid?: string; + removed: boolean; + removed_reason?: string; + yeahs?: Types.Array; + number?: number; +} + +export interface IPostMethods { + del(reason: string): Promise; + generatePostUID(length: number): Promise; + cleanedBody(): string; + cleanedMiiData(): string; + cleanedPainting(): string; + cleanedAppData(): string; + formatPainting(): PostPainting | undefined; + formatScreenshot(): PostScreenshot | undefined; + formatTopicTag(): PostTopicTag | undefined; + json(options: PostToJSONOptions, community?: HydratedCommunityDocument): PostData; +} + +export type PostModel = Model; + +export type HydratedPostDocument = HydratedDocument; \ No newline at end of file diff --git a/src/types/mongoose/report.ts b/src/types/mongoose/report.ts new file mode 100644 index 0000000..ce3d870 --- /dev/null +++ b/src/types/mongoose/report.ts @@ -0,0 +1,12 @@ +import { Model, HydratedDocument } from 'mongoose'; + +export interface IReport { + pid: string; + post_id: string; + reason: number; + created_at: Date; +} + +export type ReportModel = Model; + +export type HydratedReportDocument = HydratedDocument; \ No newline at end of file diff --git a/src/types/mongoose/settings.ts b/src/types/mongoose/settings.ts new file mode 100644 index 0000000..6f92776 --- /dev/null +++ b/src/types/mongoose/settings.ts @@ -0,0 +1,27 @@ +import { Model, HydratedDocument } from 'mongoose'; +import { SettingsData } from '@/types/miiverse/settings'; + +export interface ISettings { + pid: number; + screen_name: string; + account_status: number; + ban_lift_date: Date; + ban_reason: string; + profile_comment: string; + profile_comment_visibility: boolean; + game_skill: number; + game_skill_visibility: boolean; + birthday_visibility: boolean; + relationship_visibility: boolean; + country_visibility: boolean; + profile_favorite_community_visibility: boolean; + receive_notifications: boolean; +} + +export interface ISettingsMethods { + json(): SettingsData; +} + +export type SettingsModel = Model; + +export type HydratedSettingsDocument = HydratedDocument; \ No newline at end of file diff --git a/src/types/mongoose/subcommunity-query.ts b/src/types/mongoose/subcommunity-query.ts new file mode 100644 index 0000000..3ee3824 --- /dev/null +++ b/src/types/mongoose/subcommunity-query.ts @@ -0,0 +1,9 @@ +// TODO - Make this more generic + +export interface SubCommunityQuery { + parent: string; + owner?: number; + user_favorites?: number; + olive_community_id?: string; + community_id?: string; +} \ No newline at end of file diff --git a/src/types/node-snowflake.d.ts b/src/types/node-snowflake.d.ts new file mode 100644 index 0000000..6404ab0 --- /dev/null +++ b/src/types/node-snowflake.d.ts @@ -0,0 +1,14 @@ +declare module 'node-snowflake' { + export interface SnowflakeInitConfig { + worker_id: number; + data_center_id: number; + sequence: number; + } + + export function Server(port: number): void; + + export const Snowflake: { + init: (config: SnowflakeInitConfig) => void; + nextId: (workerId?: number, dataCenterId?: number, sequence?: number) => string; + }; +} \ No newline at end of file diff --git a/src/types/tga.d.ts b/src/types/tga.d.ts new file mode 100644 index 0000000..16eb4a2 --- /dev/null +++ b/src/types/tga.d.ts @@ -0,0 +1,58 @@ +declare module 'tga' { + export interface TGAHeader { + idLength: number; + colorMapType: number; + dataType: number; + colorMapOrigin: number; + colorMapLength: number; + colorMapDepth: number; + xOrigin: number; + yOrigin: number; + width: number; + height: number; + bitsPerPixel: number; + flags: number; + id: string; + } + + export default class TGA { + constructor(buf: Buffer, opt?: { dontFixAlpha: boolean }); + + static createTgaBuffer(width: number, height: number, pixels: Uint8Array, dontFlipY: boolean): Buffer; + + parseHeader(): void; + parseFooter(): void; + parseExtension(extensionAreaOffset: number): void; + readColor(offset: number, bytesPerPixel: number): Uint8Array; + readColorWithColorMap(offset: number): Uint8Array; + readColorAuto(offset: number, bytesPerPixel: number, isUsingColorMap: boolean): Uint8Array; + parseColorMap(): void; + setPixel(pixels: Uint8Array, idx: number, color: Uint8Array): void; + parsePixels(): void; + parse(): void; + fixForAlpha(): void; + + public dontFixAlpha: boolean; + public _buff: Buffer; + public data: Uint8Array; + public currentOffset: number; + + public header: TGAHeader; + + public width: number; + public height: number; + + public isUsingColorMap: boolean; + public isUsingRLE: boolean; + public isGray: boolean; + + public hasAlpha: boolean; + + public isFlipX: boolean; + public isFlipY: boolean; + + public colorMap: Uint8Array; + + public pixels: Uint8Array; + } +} \ No newline at end of file diff --git a/src/util.ts b/src/util.ts new file mode 100644 index 0000000..d636227 --- /dev/null +++ b/src/util.ts @@ -0,0 +1,190 @@ +import crypto from 'node:crypto'; +import { IncomingHttpHeaders } from 'node:http'; +import TGA from 'tga'; +import pako from 'pako'; +import { PNG } from 'pngjs'; +import aws from 'aws-sdk'; +import { createChannel, createClient, Metadata } from 'nice-grpc'; +import { ParsedQs } from 'qs'; +import crc32 from 'crc/crc32'; +import { ParamPack } from '@/types/common/param-pack'; +import { config } from '@/config-manager'; +import { Token } from '@/types/common/token'; + +import { FriendsDefinition } from '@pretendonetwork/grpc/friends/friends_service'; +import { FriendRequest } from '@pretendonetwork/grpc/friends/friend_request'; + +import { AccountDefinition } from '@pretendonetwork/grpc/account/account_service'; +import { GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc'; + +// * nice-grpc doesn't export ChannelImplementation so this can't be typed +const gRPCFriendsChannel = createChannel(`${config.grpc.friends.ip}:${config.grpc.friends.port}`); +const gRPCFriendsClient = createClient(FriendsDefinition, gRPCFriendsChannel); + +const gRPCAccountChannel = createChannel(`${config.grpc.account.ip}:${config.grpc.account.port}`); +const gRPCAccountClient = createClient(AccountDefinition, gRPCAccountChannel); + +const s3 = new aws.S3({ + endpoint: new aws.Endpoint(config.s3.endpoint), + accessKeyId: config.s3.key, + secretAccessKey: config.s3.secret +}); + +export function decodeParamPack(paramPack: string): ParamPack { + const values = Buffer.from(paramPack, 'base64').toString().split('\\'); + const entries = values.filter(value => value).reduce((entries: string[][], value: string, index: number) => { + if (0 === index % 2) { + entries.push([value]); + } else { + entries[Math.ceil(index / 2 - 1)].push(value); + } + + return entries; + }, []); + + return Object.fromEntries(entries); +} + +export function getPIDFromServiceToken(token: string): number { + try { + const decryptedToken = decryptToken(Buffer.from(token, 'base64')); + + if (!decryptedToken) { + return 0; + } + + const unpackedToken = unpackToken(decryptedToken); + + return unpackedToken.pid; + } catch (e) { + console.error(e); + return 0; + } +} + +export function decryptToken(token: Buffer): Buffer { + const iv = Buffer.alloc(16); + + const expectedChecksum = token.readUint32BE(); + const encryptedBody = token.subarray(4); + + const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(config.aes_key, 'hex'), iv); + + const decrypted = Buffer.concat([ + decipher.update(encryptedBody), + decipher.final() + ]); + + if (expectedChecksum !== crc32(decrypted)) { + throw new Error('Checksum did not match. Failed decrypt. Are you using the right key?'); + } + + return decrypted; +} + +export function unpackToken(token: Buffer): Token { + return { + system_type: token.readUInt8(0x0), + token_type: token.readUInt8(0x1), + pid: token.readUInt32LE(0x2), + expire_time: token.readBigUInt64LE(0x6), + title_id: token.readBigUInt64LE(0xE), + access_level: token.readInt8(0x16) + }; +} + +export function processPainting(painting: string): Buffer | null { + const paintingBuffer = Buffer.from(painting, 'base64'); + let output: Uint8Array; + + try { + output = pako.inflate(paintingBuffer); + } catch (error) { + console.error(error); + return null; + } + + const tga = new TGA(Buffer.from(output)); + const png = new PNG({ + width: tga.width, + height: tga.height + }); + + png.data = Buffer.from(tga.pixels); + + return PNG.sync.write(png); +} + +export async function uploadCDNAsset(bucket: string, key: string, data: Buffer, acl: string): Promise { + const awsPutParams = { + Body: data, + Key: key, + Bucket: bucket, + ACL: acl + }; + + await s3.putObject(awsPutParams).promise(); +} + +export async function getUserFriendPIDs(pid: number): Promise { + const response = await gRPCFriendsClient.getUserFriendPIDs({ + pid: pid + }, { + metadata: Metadata({ + 'X-API-Key': config.grpc.friends.api_key + }) + }); + + return response.pids; +} + +export async function getUserFriendRequestsIncoming(pid: number): Promise { + const response = await gRPCFriendsClient.getUserFriendRequestsIncoming({ + pid: pid + }, { + metadata: Metadata({ + 'X-API-Key': config.grpc.friends.api_key + }) + }); + + return response.friendRequests; +} + +export function getUserAccountData(pid: number): Promise { + return gRPCAccountClient.getUserData({ + pid: pid + }, { + metadata: Metadata({ + 'X-API-Key': config.grpc.account.api_key + }) + }); +} + +export function getValueFromQueryString(qs: ParsedQs, key: string): string[] { + const property = qs[key] as string | string[]; + + if (property) { + if (Array.isArray(property)) { + return property; + } else { + return [property]; + } + } + + return []; +} + +export function getValueFromHeaders(headers: IncomingHttpHeaders, key: string): string | undefined { + let header = headers[key]; + let value: string | undefined; + + if (header) { + if (Array.isArray(header)) { + header = header[0]; + } + + value = header; + } + + return value; +} \ No newline at end of file diff --git a/src/util/CommunityPostGen.js b/src/util/CommunityPostGen.js deleted file mode 100644 index c912a23..0000000 --- a/src/util/CommunityPostGen.js +++ /dev/null @@ -1,258 +0,0 @@ -const xmlbuilder = require("xmlbuilder"); -const moment = require("moment"); -const database = require('../database'); - -class CommunityPostGen { - /* TODO lots of stubs and constants in here */ - static async PostsResponse(posts, community) { - let xml = xmlbuilder.create("result") - .e("has_error", "0").up() - .e("version", "1").up() - .e("request_name", "posts").up() - .e("topic") - .e("community_id", community.community_id).up() - .up() - .e("posts"); - for (let i = 0; i < posts.length; i++) { - xml = xml.e("post") - .e("app_data", posts[i].app_data).up() - .e("body", posts[i].body).up() - .e("community_id", community.id).up() - .e("country_id", "254").up() - .e("created_at", moment(posts[i].created_at).format("YYYY-MM-DD hh:mm:ss")).up() - .e("feeling_id", "1").up() - .e("id", posts[i].id).up() - .e("is_autopost", "0").up() - .e("is_community_private_autopost", "0").up() - .e("is_spoiler", "0").up() - .e("is_app_jumpable", "0").up() - .e("empathy_count", posts[i].empathy_count).up() - .e("language_id", "1").up() - .e("number", "0").up(); - if (posts[i].painting) { - xml = xml.e("painting") - .e("format", "tga").up() - .e("content", posts[i].painting).up() - .e("size", posts[i].painting.length).up() - .e("url", "https://s3.amazonaws.com/olv-public/pap/WVW69koebmETvBVqm1").up() - .up(); - } - xml = xml.e("pid", posts[i].pid).up() - .e("platform_id", "1").up() - .e("region_id", "4").up() - .e("reply_count", "0").up() - .e("screen_name", posts[i].screen_name).up() - .e("title_id", community.title_ids[0]).up() - .up(); - } - - return xml.end({ pretty: true, allowEmpty: true }); - } - - static async PostsResponseWithMii(posts, community) { - let xml = xmlbuilder.create("result") - .e("has_error", "0").up() - .e("version", "1").up() - .e("request_name", "posts").up() - .e("topic") - .e("community_id", community.community_id).up() - .up() - .e("posts"); - for (let i = 0; i < posts.length; i++) { - xml = xml.e("post") - .e("app_data", posts[i].app_data).up() - .e("body", posts[i].body).up() - .e("community_id", community.community_id).up() - .e("country_id", "254").up() - .e("created_at", moment(posts[i].created_at).format('YYYY-MM-DD HH:MM:SS')).up() - .e("feeling_id", "1").up() - .e("id", posts[i].id).up() - .e("is_autopost", "0").up() - .e("is_community_private_autopost", "0").up() - .e("is_spoiler", "0").up() - .e("is_app_jumpable", "0").up() - .e("empathy_count", posts[i].empathy_count).up() - .e("language_id", "1").up() - .e("mii", posts[i].mii).up() - .e("mii_face_url", posts[i].mii_face_url).up() - .e("number", "0").up(); - if (posts[i].painting) { - xml = xml.e("painting") - .e("format", "tga").up() - .e("content", posts[i].painting).up() - .e("size", posts[i].painting.length).up() - .e("url", "https://s3.amazonaws.com/olv-public/pap/WVW69koebmETvBVqm1").up() - .up(); - } - xml = xml.e("pid", posts[i].id).up() - .e("platform_id", posts[i].platform_id).up() - .e("region_id", posts[i].region_id).up() - .e("reply_count", posts[i].reply_count).up() - .e("screen_name", posts[i].screen_name).up() - .e("title_id", posts[i].title_id).up() - .up(); - } - - return xml.end({ pretty: true, allowEmpty: true }); - } - - static async EmptyResponse() { - const xml = xmlbuilder.create("result") - .e("has_error", "0").up() - .e("version", "1").up(); - return xml.end({ pretty: true, allowEmpty: true }); - } - - static async Communities(community) { - const xml = xmlbuilder.create("result") - .e("has_error", "0").up() - .e("version", "1").up() - .e("request_name", "communities").up() - .e("communities") - .e("community") - .e('olive_community_id', community.community_id).up() - .e('community_id', community.community_id).up() - .e("name", community.name).up() - .e("description", community.description).up() - .e("icon").up() - .e("icon_3ds").up() - .e("pid").up() - .e("app_data").up() - .e("is_user_community", 0).up() - .up() - .e("community") - .e('olive_community_id', community.community_id + 100).up() - .e('community_id', community.community_id + 100).up() - .e("name", community.name + '- Nintendo Levels').up() - .e("description", community.description).up() - .e("icon").up() - .e("icon_3ds").up() - .e("pid").up() - .e("app_data", 'TVZNSQI').up() - .e("is_user_community", 0).up() - .up() - .e("community") - .e('olive_community_id', community.community_id + 200).up() - .e('community_id', community.community_id + 200).up() - .e("name", community.name + '- User Levels').up() - .e("description", community.description).up() - .e("icon").up() - .e("icon_3ds").up() - .e("pid").up() - .e("app_data", 'TVZNSQE').up() - .e("is_user_community", 0).up() - .up() - .up(); - return xml.end({ pretty: true, allowEmpty: true }); - } - /* TODO Again, some constants */ - static async SinglePostResponse(post) { - let xml = xmlbuilder.create("result") - .e("has_error", "0").up() - .e("version", "1").up() - .e("post"); - if (post.app_data) { - xml = xml.e("app_data", post.app_data).up(); - } - xml = xml.e("body", post.body).up() - .e("community_id", post.community_id).up() - .e("country_id", "254").up() - .e("created_at", post.created_at).up() - .e("feeling_id", "1").up() - .e("id", post.id).up() - .e("is_autopost", "0").up() - .e("is_community_private_autopost", "0").up() - .e("is_spoiler", "0").up() - .e("is_app_jumpable", "0").up() - .e("empathy_count", post.empathy_count).up() - .e("language_id", "1").up() - .e("number", "0").up(); - if (post.painting) { - xml = xml.e("painting") - .e("format", "tga").up() - .e("content", post.painting).up() - .e("size", post.painting.length).up() - .e("url", "https://s3.amazonaws.com/olv-public/pap/WVW69koebmETvBVqm1").up() - .up(); - } - xml = xml.e("pid", post.pid).up() - .e("platform_id", "1").up() - .e("region_id", "4").up() - .e("reply_count", "0").up() - .e("screen_name", post.screen_name).up() - .e("title_id", post.title_id).up() - .up(); - return xml.end({ pretty: true, allowEmpty: true }); - } - - static async topics(communities) { - const expirationDate = moment().add(2, 'days'); - let xml = xmlbuilder.create("result") - .e("has_error", "0").up() - .e("version", "1").up() - .e("request_name", "topics").up() - .e("expire", expirationDate.format('YYYY-MM-DD HH:MM:SS')).up() - .e("topics"); - for (const community of communities) { - let posts = await database.getPostsByCommunity(community, 30); - xml = xml.e('topic') - .e('empathy_count', community.empathy_count).up() - .e('has_shop_page', community.has_shop_page).up() - .e('icon', community.icon).up() - .e('title_ids'); - community.title_ids.forEach(function (title_id) { - xml = xml.e('title_id', title_id).up() - }) - xml = xml.up() - .e('title_id', community.title_ids[0]).up() - .e('community_id', community.community_id).up() - .e('is_recommended', community.is_recommended).up() - .e('name', community.name).up() - .e("people"); - for (const post of posts) { - let newBody = ''; - if(post.body) - newBody = post.body.replace( /[\r\n]+/gm, ''); - xml = xml.e("person") - .e("posts") - .e("post") - .e("body", newBody).up() - .e("community_id", community.community_id).up() - .e("country_id", post.country_id).up() - .e("created_at", moment(post.created_at).format('YYYY-MM-DD HH:MM:SS')).up() - .e("feeling_id", post.feeling_id).up() - .e("id", post.id).up() - .e("is_autopost", post.is_autopost).up() - .e("is_community_private_autopost", post.is_community_private_autopost).up() - .e("is_spoiler", post.is_spoiler).up() - .e("is_app_jumpable", post.is_app_jumpable).up() - .e("empathy_count", post.empathy_count).up() - .e("language_id", post.language_id).up() - .e("mii", post.mii).up() - .e("mii_face_url", "https://s3.amazonaws.com/olv-public/pap/WVW69koebmETvBVqm1").up(); - xml = xml.e("number", "0").up(); - if (post.painting) { - xml = xml.e("painting") - .e("format", "tga").up() - .e("content", post.painting.replace( /[\r\n]+/gm, "" )).up() - .e("size", post.painting.length).up() - .e("url", "https://s3.amazonaws.com/olv-public/pap/WVW69koebmETvBVqm1").up() - .up(); - } - xml = xml.e("pid", post.pid).up() - .e("platform_id", post.platform_id).up() - .e("region_id", post.region_id).up() - .e("reply_count", post.reply_count).up() - .e("screen_name", post.screen_name).up() - .e("title_id", post.title_id).up() - .up().up().up(); - } - xml = xml.up().up() - } - return xml.end({ pretty: true, allowEmpty: true }); - } -} - -if (typeof module !== "undefined") { - module.exports = CommunityPostGen; -} diff --git a/src/util/peoplePostGen.js b/src/util/peoplePostGen.js deleted file mode 100644 index 6ce90b0..0000000 --- a/src/util/peoplePostGen.js +++ /dev/null @@ -1,150 +0,0 @@ -const xmlbuilder = require("xmlbuilder"); -const moment = require("moment"); - -class CommunityPostGen { - /* TODO lots of stubs and constants in here */ - static async PostsResponse(posts, community) { - const expirationDate = moment().add(11, 'days'); - - let xml = xmlbuilder.create("result") - .e("has_error", "0").up() - .e("version", "1").up() - .e("expire", expirationDate.format('YYYY-MM-DD HH:MM:SS')).up() - .e("request_name", "people").up() - .e("people"); - for (let i = 0; i < posts.length; i++) { - xml = xml.e("person") - .e("posts") - .e("post") - .e("body", posts[i].body).up() - .e("community_id", community.community_id).up() - .e("country_id", "254").up() - .e("created_at", posts[i].created_at).up() - .e("feeling_id", "1").up() - .e("id", posts[i].id).up() - .e("is_autopost", "0").up() - .e("is_community_private_autopost", "0").up() - .e("is_spoiler", "0").up() - .e("is_app_jumpable", "0").up() - .e("empathy_count", posts[i].empathy_count).up() - .e("language_id", "1").up(); - xml = xml.e("number", "0").up(); - if (posts[i].painting) { - xml = xml.e("painting") - .e("format", "tga").up() - .e("content", posts[i].painting).up() - .e("size", posts[i].painting.length).up() - .e("url", "https://s3.amazonaws.com/olv-public/pap/WVW69koebmETvBVqm1").up() - .up(); - } - xml = xml.e("pid", posts[i].pid).up() - .e("platform_id", "1").up() - .e("region_id", "4").up() - .e("reply_count", "0").up() - .e("screen_name", posts[i].screen_name).up() - .e("title_id", posts[i].title_id).up() - .up().up().up(); - } - - return xml.end({ pretty: true, allowEmpty: true }); - } - - static async PostsResponseWithMii(posts, community) { - let xml = xmlbuilder.create("result") - .e("has_error", "0").up() - .e("version", "1").up() - .e("request_name", "posts").up() - .e("topic") - .e("community_id", community.community_id).up() - .up() - .e("posts"); - for (let i = 0; i < posts.length; i++) { - xml = xml.e("person") - .e("posts") - .e("post") - .e("body", posts[i].body).up() - .e("community_id", community.community_id).up() - .e("country_id", "254").up() - .e("created_at", posts[i].created_at).up() - .e("feeling_id", "1").up() - .e("id", posts[i].id).up() - .e("is_autopost", "0").up() - .e("is_community_private_autopost", "0").up() - .e("is_spoiler", "0").up() - .e("is_app_jumpable", "0").up() - .e("empathy_count", posts[i].empathy_count).up() - .e("language_id", "1").up() - .e("mii", posts[i].mii).up() - .e("mii_face_url", posts[i].mii_face_url).up() - .e("number", "0").up(); - if (posts[i].painting) { - xml = xml.e("painting") - .e("format", "tga").up() - .e("content", posts[i].painting).up() - .e("size", posts[i].painting.length).up() - .e("url", "https://s3.amazonaws.com/olv-public/pap/WVW69koebmETvBVqm1").up() - .up(); - } - xml = xml.e("pid", posts[i].pid).up() - .e("platform_id", "1").up() - .e("region_id", "4").up() - .e("reply_count", "0").up() - .e("screen_name", posts[i].screen_name).up() - .e("title_id", posts[i].title_id).up() - .up(); - } - - return xml.end({ pretty: true, allowEmpty: true }); - } - - static async EmptyResponse() { - const xml = xmlbuilder.create("result") - .e("has_error", "0").up() - .e("version", "1").up(); - return xml.end({ pretty: true, allowEmpty: true }); - } - - /* TODO Again, some constants */ - static async SinglePostResponse(post) { - let xml = xmlbuilder.create("result") - .e("has_error", "0").up() - .e("version", "1").up() - .e("post"); - if (post.app_data) { - xml = xml.e("app_data", post.app_data).up(); - } - xml = xml.e("body", post.body).up() - .e("community_id", post.community_id).up() - .e("country_id", "254").up() - .e("created_at", post.created_at).up() - .e("feeling_id", "1").up() - .e("id", post.id).up() - .e("is_autopost", "0").up() - .e("is_community_private_autopost", "0").up() - .e("is_spoiler", "0").up() - .e("is_app_jumpable", "0").up() - .e("empathy_count", post.empathy_count).up() - .e("language_id", "1").up() - .e("number", "0").up(); - if (post.painting) { - xml = xml.e("painting") - .e("format", "tga").up() - .e("content", post.painting).up() - .e("size", post.painting.length).up() - .e("url", "https://s3.amazonaws.com/olv-public/pap/WVW69koebmETvBVqm1").up() - .up(); - } - xml = xml.e("pid", post.pid).up() - .e("platform_id", "1").up() - .e("region_id", "4").up() - .e("reply_count", "0").up() - .e("screen_name", post.screen_name).up() - .e("title_id", post.title_id).up() - .up(); - return xml.end({ pretty: true, allowEmpty: true }); - } -} - -if (typeof module !== "undefined") { - module.exports = CommunityPostGen; -} diff --git a/src/util/util.js b/src/util/util.js deleted file mode 100644 index b26bb84..0000000 --- a/src/util/util.js +++ /dev/null @@ -1,164 +0,0 @@ -const crypto = require('crypto'); -const NodeRSA = require('node-rsa'); -const fs = require('fs-extra'); -const database = require('../database'); -const config = require('../../config.json'); -const xmlParser = require('xml2json'); -const request = require("request"); -const moment = require('moment'); -const { USER } = require('../models/user'); -let TGA = require('tga'); -let pako = require('pako'); -let PNG = require('pngjs').PNG; -const path = require('path') - - -let methods = { - processUser: function(pid) { - return new Promise(async function(resolve, reject) { - let userObject = await database.getUserByPID(pid); - if(userObject != null) - resolve(userObject); - else - { - await request({ - url: "http://" + config.account_server + "/v1/api/miis?pids=" + pid, - headers: { - 'X-Nintendo-Client-ID': 'a2efa818a34fa16b8afbc8a74eba3eda', - 'X-Nintendo-Client-Secret': 'c91cdb5658bd4954ade78533a339cf9a' - } - }, function (error, response, body) { - if (!error && response.statusCode === 200) { - let xml = xmlParser.toJson(body, {object: true}); - const newUsr = { - pid: pid, - created_at: moment().format('YYYY-MM-DD HH:mm:SS'), - user_id: xml.miis.mii.user_id, - account_status: 0, - mii: xml.miis.mii.data, - official: false - }; - const newUsrObj = new USER(newUsr); - newUsrObj.save(); - resolve(newUsr); - } - else - { - console.log('fail'); - reject(); - } - - }); - - } - }); - }, - decodeParamPack: function (paramPack) { - /* Decode base64 */ - let dec = Buffer.from(paramPack, "base64").toString("ascii"); - /* Remove starting and ending '/', split into array */ - dec = dec.slice(1, -1).split("\\"); - /* Parameters are in the format [name, val, name, val]. Copy into out{}. */ - const out = {}; - for (let i = 0; i < dec.length; i += 2) { - out[dec[i].trim()] = dec[i + 1].trim(); - } - return out; - }, - processServiceToken: function(token) { - try - { - let B64token = Buffer.from(token, 'base64'); - let decryptedToken = this.decryptToken(B64token); - return decryptedToken.readUInt32LE(0x2); - } - catch(e) - { - console.log(e) - return null; - } - - }, - decryptToken: function(token) { - // Access and refresh tokens use a different format since they must be much smaller - // Assume a small length means access or refresh token - if (token.length <= 32) { - const cryptoPath = path.normalize(`${__dirname}/../certs/access`); - const aesKey = Buffer.from(fs.readFileSync(`${cryptoPath}/aes.key`, { encoding: 'utf8' }), 'hex'); - - const iv = Buffer.alloc(16); - - const decipher = crypto.createDecipheriv('aes-128-cbc', aesKey, iv); - - let decryptedBody = decipher.update(token); - decryptedBody = Buffer.concat([decryptedBody, decipher.final()]); - - return decryptedBody; - } - - const cryptoPath = path.normalize(`${__dirname}/../certs/access`); - - const cryptoOptions = { - private_key: fs.readFileSync(`${cryptoPath}/private.pem`), - hmac_secret: config.secret - }; - - const privateKey = new NodeRSA(cryptoOptions.private_key, 'pkcs1-private-pem', { - environment: 'browser', - encryptionScheme: { - 'hash': 'sha256', - } - }); - - const cryptoConfig = token.subarray(0, 0x82); - const signature = token.subarray(0x82, 0x96); - const encryptedBody = token.subarray(0x96); - - const encryptedAESKey = cryptoConfig.subarray(0, 128); - const point1 = cryptoConfig.readInt8(0x80); - const point2 = cryptoConfig.readInt8(0x81); - - const iv = Buffer.concat([ - Buffer.from(encryptedAESKey.subarray(point1, point1 + 8)), - Buffer.from(encryptedAESKey.subarray(point2, point2 + 8)) - ]); - - const decryptedAESKey = privateKey.decrypt(encryptedAESKey); - - const decipher = crypto.createDecipheriv('aes-128-cbc', decryptedAESKey, iv); - - let decryptedBody = decipher.update(encryptedBody); - decryptedBody = Buffer.concat([decryptedBody, decipher.final()]); - - const hmac = crypto.createHmac('sha1', cryptoOptions.hmac_secret).update(decryptedBody); - const calculatedSignature = hmac.digest(); - - if (Buffer.compare(calculatedSignature, signature) !== 0) { - console.log('Token signature did not match'); - return null; - } - - return decryptedBody; - }, - processPainting: function (painting) { - let paintingBuffer = Buffer.from(painting, 'base64'); - let output = ''; - try - { - output = pako.inflate(paintingBuffer); - } - catch (err) - { - console.error(err); - } - let tga = new TGA(Buffer.from(output)); - let png = new PNG({ - width: tga.width, - height: tga.height - }); - png.data = tga.pixels; - let pngBuffer = PNG.sync.write(png); - return `data:image/png;base64,${pngBuffer.toString('base64')}`; - }, -}; -exports.data = methods; diff --git a/test/test.ts b/test/test.ts new file mode 100644 index 0000000..2b7233c --- /dev/null +++ b/test/test.ts @@ -0,0 +1,298 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import crypto from 'node:crypto'; +import newman from 'newman'; +import { Collection, CollectionDefinition } from 'postman-collection'; +import qs from 'qs'; +import axios from 'axios'; +import { create as parseXML } from 'xmlbuilder2'; +import { table } from 'table'; +import ora from 'ora'; +import dotenv from 'dotenv'; +import colors from 'colors'; + +import communitiesCollection from '../postman/collections/Communities.json'; +import peopleCollection from '../postman/collections/People.json'; + +const PeopleCollection: CollectionDefinition = peopleCollection as CollectionDefinition; +const CommunitiesCollection: CollectionDefinition = communitiesCollection as CollectionDefinition; + +dotenv.config(); +colors.enable(); + +interface TestResult { + collection: string; + name: string; + url: string; + query: string; + assertion: string; + error?: string +} + +const USERNAME = process.env.PN_MIIVERSE_API_TESTING_USERNAME?.trim() || ''; +const PASSWORD = process.env.PN_MIIVERSE_API_TESTING_PASSWORD?.trim() || ''; +const DEVICE_ID = process.env.PN_MIIVERSE_API_TESTING_DEVICE_ID?.trim() || ''; +const SERIAL_NUMBER = process.env.PN_MIIVERSE_API_TESTING_SERIAL_NUMBER?.trim() || ''; +const CERTIFICATE = process.env.PN_MIIVERSE_API_TESTING_CONSOLE_CERT?.trim() || ''; + +if (!USERNAME) { + throw new Error('PNID username missing. Required for requesting service tokens. Set PN_MIIVERSE_API_TESTING_USERNAME'); +} + +if (!PASSWORD) { + throw new Error('PNID password missing. Required for requesting service tokens. Set PN_MIIVERSE_API_TESTING_PASSWORD'); +} + +if (!DEVICE_ID) { + throw new Error('Console device ID missing. Required for requesting service tokens. Set PN_MIIVERSE_API_TESTING_DEVICE_ID'); +} + +if (!SERIAL_NUMBER) { + throw new Error('Console serial number missing. Required for requesting service tokens. Set PN_MIIVERSE_API_TESTING_SERIAL_NUMBER'); +} + +if (!CERTIFICATE) { + throw new Error('Console certificate missing. Required for requesting service tokens. Set PN_MIIVERSE_API_TESTING_CONSOLE_CERT'); +} + +const BASE_URL = 'https://account.pretendo.cc'; +const API_URL = `${BASE_URL}/v1/api`; +const MAPPED_IDS_URL = `${API_URL}/admin/mapped_ids`; +const ACCESS_TOKEN_URL = `${API_URL}/oauth20/access_token/generate`; +const SERVICE_TOKEN_URL = `${API_URL}/provider/service_token/@me?client_id=87cd32617f1985439ea608c2746e4610`; + +const DEFAULT_HEADERS = { + 'X-Nintendo-Client-ID': 'a2efa818a34fa16b8afbc8a74eba3eda', + 'X-Nintendo-Client-Secret': 'c91cdb5658bd4954ade78533a339cf9a', + 'X-Nintendo-Device-ID': DEVICE_ID, + 'X-Nintendo-Serial-Number': SERIAL_NUMBER, + 'X-Nintendo-Device-Cert': CERTIFICATE +}; + +export function nintendoPasswordHash(password: string, pid: number): string { + const pidBuffer = Buffer.alloc(4); + pidBuffer.writeUInt32LE(pid); + + const unpacked = Buffer.concat([ + pidBuffer, + Buffer.from('\x02\x65\x43\x46'), + Buffer.from(password) + ]); + + return crypto.createHash('sha256').update(unpacked).digest().toString('hex'); +} + +async function apiGetRequest(url: string, headers = {}): Promise> { + const response = await axios.get(url, { + headers: Object.assign(headers, DEFAULT_HEADERS), + validateStatus: () => true + }); + + const data: Record = parseXML(response.data).end({ format: 'object' }); + + if (data.errors) { + throw new Error(data.errors.error.message); + } + + if (data.error) { + throw new Error(data.error.message); + } + + return data; +} + +async function apiPostRequest(url: string, body: string): Promise> { + const response = await axios.post(url, body, { + headers: DEFAULT_HEADERS, + validateStatus: () => true, + }); + + const data: Record = parseXML(response.data).end({ format: 'object' }); + + if (data.errors) { + throw new Error(data.errors.error.message); + } + + if (data.error) { + throw new Error(data.error.message); + } + + return data; +} + +async function getPID(username: string): Promise { + const response = await apiGetRequest(`${MAPPED_IDS_URL}?input_type=user_id&output_type=pid&input=${username}`); + + return Number(response.mapped_ids.mapped_id.out_id); +} + +async function getAccessToken(username: string, passwordHash: string): Promise { + const data = qs.stringify({ + grant_type: 'password', + user_id: username, + password: passwordHash, + password_type: 'hash', + }); + + const response = await apiPostRequest(ACCESS_TOKEN_URL, data); + + return response.OAuth20.access_token.token; +} + +async function getMiiverseServiceToken(accessToken: string): Promise { + const response = await apiGetRequest(SERVICE_TOKEN_URL, { + 'X-Nintendo-Title-ID': '0005001010040100', + Authorization: `Bearer ${accessToken}` + }); + + return response.service_token.token; +} + +function runNewmanTest(collection: string | Collection | CollectionDefinition, variables: Record): Promise { + return new Promise((resolve, reject) => { + newman.run({ + collection: collection, + reporters: ['json'], + envVar: Object.entries(variables).map(entry => ({ key: entry[0], value: entry[1] })), + globals: variables, + globalVar: Object.entries(variables).map(entry => ({ key: entry[0], value: entry[1] })), + }, (error, summary) => { + if (error) { + reject(error); + } else { + resolve(createTestResults(summary)); + } + }); + }); +} + +function communitiesRoutesTest(serviceToken: string): Promise { + // TODO - Make this more dynamic? + return runNewmanTest(CommunitiesCollection, { + DOMAIN: 'api.olv.pretendo.cc', + ServiceToken: serviceToken, + // TODO - Change these names. Should not be game-specific + PP_Splatoon: 'XHRpdGxlX2lkXDE0MDczNzUxNTM1MjI5NDRcYWNjZXNzX2tleVwwXHBsYXRmb3JtX2lkXDFccmVnaW9uX2lkXDJcbGFuZ3VhZ2VfaWRcMVxjb3VudHJ5X2lkXDExMFxhcmVhX2lkXDBcbmV0d29ya19yZXN0cmljdGlvblwwXGZyaWVuZF9yZXN0cmljdGlvblwwXHJhdGluZ19yZXN0cmljdGlvblwyMFxyYXRpbmdfb3JnYW5pemF0aW9uXDBcdHJhbnNmZXJhYmxlX2lkXDEyNzU2MTQ0ODg0NDUzODk4NzgyXHR6X25hbWVcQW1lcmljYS9OZXdfWW9ya1x1dGNfb2Zmc2V0XC0xNDQwMFxyZW1hc3Rlcl92ZXJzaW9uXDBc', + PP_MarioVsDK: 'XHRpdGxlX2lkXDE0MDczNzUxNTMzMzcwODhcYWNjZXNzX2tleVw2OTI0NzQ1MTBccGxhdGZvcm1faWRcMVxyZWdpb25faWRcMlxsYW5ndWFnZV9pZFwxXGNvdW50cnlfaWRcNDlcYXJlYV9pZFwwXG5ldHdvcmtfcmVzdHJpY3Rpb25cMFxmcmllbmRfcmVzdHJpY3Rpb25cMFxyYXRpbmdfcmVzdHJpY3Rpb25cMTdccmF0aW5nX29yZ2FuaXphdGlvblwxXHRyYW5zZmVyYWJsZV9pZFw3NjA4MjAyOTE2MDc1ODg0NDI1XHR6X25hbWVcUGFjaWZpYy9NaWR3YXlcdXRjX29mZnNldFwtMzk2MDBc', + PP_Bad_TID: 'XHRpdGxlX2lkXDEyMzRcYWNjZXNzX2tleVwwXHBsYXRmb3JtX2lkXDFccmVnaW9uX2lkXDJcbGFuZ3VhZ2VfaWRcMVxjb3VudHJ5X2lkXDExMFxhcmVhX2lkXDBcbmV0d29ya19yZXN0cmljdGlvblwwXGZyaWVuZF9yZXN0cmljdGlvblwwXHJhdGluZ19yZXN0cmljdGlvblwyMFxyYXRpbmdfb3JnYW5pemF0aW9uXDBcdHJhbnNmZXJhYmxlX2lkXDEyNzU2MTQ0ODg0NDUzODk4NzgyXHR6X25hbWVcQW1lcmljYS9OZXdfWW9ya1x1dGNfb2Zmc2V0XC0xNDQwMFxyZW1hc3Rlcl92ZXJzaW9uXDBc', + PP_ACPlaza: 'XHRpdGxlX2lkXDE0MDczNzUxNTMzMjE0NzJcYWNjZXNzX2tleVwwXHBsYXRmb3JtX2lkXDFccmVnaW9uX2lkXDJcbGFuZ3VhZ2VfaWRcMVxjb3VudHJ5X2lkXDExMFxhcmVhX2lkXDBcbmV0d29ya19yZXN0cmljdGlvblwwXGZyaWVuZF9yZXN0cmljdGlvblwwXHJhdGluZ19yZXN0cmljdGlvblwyMFxyYXRpbmdfb3JnYW5pemF0aW9uXDBcdHJhbnNmZXJhYmxlX2lkXDEyNzU2MTQ0ODg0NDUzODk4NzgyXHR6X25hbWVcQW1lcmljYS9OZXdfWW9ya1x1dGNfb2Zmc2V0XC0xNDQwMFxyZW1hc3Rlcl92ZXJzaW9uXDBc', + 'PP_Bad Format': 'XHR' + }); +} + +function peopleRoutesTest(serviceToken: string): Promise { + // TODO - Make this more dynamic? + return runNewmanTest(PeopleCollection, { + DOMAIN: 'api.olv.pretendo.cc', + ServiceToken: serviceToken, + // TODO - Change this name. Should not be game-specific + PP_Splatoon: 'XHRpdGxlX2lkXDE0MDczNzUxNTM1MjI5NDRcYWNjZXNzX2tleVwwXHBsYXRmb3JtX2lkXDFccmVnaW9uX2lkXDJcbGFuZ3VhZ2VfaWRcMVxjb3VudHJ5X2lkXDExMFxhcmVhX2lkXDBcbmV0d29ya19yZXN0cmljdGlvblwwXGZyaWVuZF9yZXN0cmljdGlvblwwXHJhdGluZ19yZXN0cmljdGlvblwyMFxyYXRpbmdfb3JnYW5pemF0aW9uXDBcdHJhbnNmZXJhYmxlX2lkXDEyNzU2MTQ0ODg0NDUzODk4NzgyXHR6X25hbWVcQW1lcmljYS9OZXdfWW9ya1x1dGNfb2Zmc2V0XC0xNDQwMFxyZW1hc3Rlcl92ZXJzaW9uXDBc', + }); +} + +async function main(): Promise { + const tokensSpinner = ora('Acquiring account tokens').start(); + + const pid = await getPID(USERNAME); + const passwordHash = nintendoPasswordHash(PASSWORD, pid); + const accessToken = await getAccessToken(USERNAME, passwordHash); + const serviceToken = await getMiiverseServiceToken(accessToken); + + tokensSpinner.succeed(); + + const testsSpinner = ora('Running tests').start(); + + const results: TestResult[] = [ + ...await communitiesRoutesTest(serviceToken), + ...await peopleRoutesTest(serviceToken) + ]; + + const passed = results.filter(result => !result.error); + const failed = results.filter(result => result.error); + + if (failed.length !== 0) { + testsSpinner.warn('Some tests have failed! See below for details'); + } else { + testsSpinner.succeed('All tests passed!'); + } + + const testsOverviewData = [ + ['Tests Ran'.cyan, results.length.toString().cyan], + ['Passed'.green, passed.length.toString().green] + ]; + + if (failed.length === 0) { + testsOverviewData.push(['Failed'.red, failed.length.toString().green]); + } else { + testsOverviewData.push(['Failed'.red, failed.length.toString().red]); + } + + const config = { + singleLine: true, + border: { + topBody: '─', + topJoin: '┬', + topLeft: '┌', + topRight: '┐', + + bottomBody: '─', + bottomJoin: '┴', + bottomLeft: '└', + bottomRight: '┘', + + bodyLeft: '│', + bodyRight: '│', + bodyJoin: '│', + + joinBody: '─', + joinLeft: '├', + joinRight: '┤', + joinJoin: '┼' + } + }; + + console.log(table(testsOverviewData, config)); + + if (failed.length !== 0) { + console.log('Failed tests:\n'.red.underline.italic.bold); + for (const test of failed) { + console.log('Collection:'.bold, test.collection.red.bold); + console.log('Test Name:'.bold, test.name.red.bold); + console.log('URL:'.bold, `${test.url}${test.query ? '?' + test.query : ''}`.red.bold); + console.log('Message:'.bold, test.error?.red.bold); + console.log('\n'); + } + } +} + +main(); + +function createTestResults(summary: newman.NewmanRunSummary): TestResult[] { + const results: TestResult[] = []; + + for (const execution of summary.run.executions) { + const request = execution.request; + for (const assertion of execution.assertions) { + const result: TestResult = { + collection: summary.collection.name, + name: execution.item.name, + url: `${request.url.protocol}://${request.url.host?.join('.')}/${request.url.path?.join('/')}`, + query: qs.stringify(request.url.query.all().reduce((object: Record, item: { disabled?: boolean; key: string | null; value: string | null; }) => { + if (!item.disabled && item.key && item.value) { + object[item.key] = item.value; + } + return object; + }, {})), + assertion: assertion.assertion + }; + + if (assertion.error) { + result.error = `${assertion.error.name}: ${assertion.error.message}`; + } + + results.push(result); + } + } + + return results; +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..b332a95 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "strict": true, + "sourceMap": true, + "resolveJsonModule": true, + "module": "commonjs", + "esModuleInterop": true, + "moduleResolution": "node", + "baseUrl": "src", + "outDir": "dist", + "allowJs": true, + "target": "es2022", + "noEmitOnError": true, + "noImplicitAny": true, + "strictPropertyInitialization": true, + "paths": { + "@/*": ["./*"] + } + }, + "include": ["src"] +} \ No newline at end of file