From a2fba76f9be4db20a869e230e406c5e9a1bf3d00 Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Mon, 9 Jan 2023 03:31:35 -0300 Subject: [PATCH 1/6] bad init to db --- package-lock.json | 2304 +++++++++++++++++++++++++++++++++++++++++- package.json | 1 + src/express_route.ts | 20 +- src/mirror.ts | 1 - src/repoConfig.ts | 196 +++- 5 files changed, 2479 insertions(+), 43 deletions(-) diff --git a/package-lock.json b/package-lock.json index c225ae4..09f6122 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "cron": "^2.1.0", "express": "^4.18.2", "lzma-native": "^8.0.6", + "mongodb": "^4.13.0", "openpgp": "^5.5.0", "tar": "^6.1.13", "yaml": "^2.2.1", @@ -54,6 +55,1081 @@ "tunnel": "^0.0.6" } }, + "node_modules/@aws-crypto/ie11-detection": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-2.0.2.tgz", + "integrity": "sha512-5XDMQY98gMAf/WRTic5G++jfmS/VLM0rwpiOpaainKi4L0nqWMSB1SzsrEG5rjFZGYN6ZAefO+/Yta2dFM0kMw==", + "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": "2.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-2.0.0.tgz", + "integrity": "sha512-rYXOQ8BFOaqMEHJrLHul/25ckWH6GTJtdLSajhlqGMx0PmSueAuvboCuZCTqEKlxR8CQOwRarxYMZZSYlhRA1A==", + "optional": true, + "dependencies": { + "@aws-crypto/ie11-detection": "^2.0.0", + "@aws-crypto/sha256-js": "^2.0.0", + "@aws-crypto/supports-web-crypto": "^2.0.0", + "@aws-crypto/util": "^2.0.0", + "@aws-sdk/types": "^3.1.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": "2.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-2.0.0.tgz", + "integrity": "sha512-VZY+mCY4Nmrs5WGfitmNqXzaE873fcIZDu54cbaDaaamsaTOP1DBImV9F4pICc3EHjQXujyE8jig+PFCaew9ig==", + "optional": true, + "dependencies": { + "@aws-crypto/util": "^2.0.0", + "@aws-sdk/types": "^3.1.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": "2.0.2", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-2.0.2.tgz", + "integrity": "sha512-6mbSsLHwZ99CTOOswvCRP3C+VCWnzBf+1SnbWxzzJ9lR0mA0JnY2JEAhp8rqmTE0GPFy88rrM27ffgp62oErMQ==", + "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": "2.0.2", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-2.0.2.tgz", + "integrity": "sha512-Lgu5v/0e/BcrZ5m/IWqzPUf3UYFTy/PpeED+uc9SWUR1iZQL8XXbGQg10UfllwwBryO3hFF5dizK+78aoXC1eA==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.110.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/abort-controller": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.226.0.tgz", + "integrity": "sha512-cJVzr1xxPBd08voknXvR0RLgtZKGKt6WyDpH/BaPCu3rfSqWCDZKzwqe940eqosjmKrxC6pUZNKASIqHOQ8xxQ==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.245.0.tgz", + "integrity": "sha512-c5briTS05rAioO5b84bVng9M1KyAXcxJtDHeuoeAAZBuU+Dd0Scg3vyXyAFlGI+TsNyxqHAqqRdAoG4WNxJo/Q==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "2.0.0", + "@aws-crypto/sha256-js": "2.0.0", + "@aws-sdk/client-sts": "3.245.0", + "@aws-sdk/config-resolver": "3.234.0", + "@aws-sdk/credential-provider-node": "3.245.0", + "@aws-sdk/fetch-http-handler": "3.226.0", + "@aws-sdk/hash-node": "3.226.0", + "@aws-sdk/invalid-dependency": "3.226.0", + "@aws-sdk/middleware-content-length": "3.226.0", + "@aws-sdk/middleware-endpoint": "3.226.0", + "@aws-sdk/middleware-host-header": "3.226.0", + "@aws-sdk/middleware-logger": "3.226.0", + "@aws-sdk/middleware-recursion-detection": "3.226.0", + "@aws-sdk/middleware-retry": "3.235.0", + "@aws-sdk/middleware-serde": "3.226.0", + "@aws-sdk/middleware-signing": "3.226.0", + "@aws-sdk/middleware-stack": "3.226.0", + "@aws-sdk/middleware-user-agent": "3.226.0", + "@aws-sdk/node-config-provider": "3.226.0", + "@aws-sdk/node-http-handler": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/smithy-client": "3.234.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/url-parser": "3.226.0", + "@aws-sdk/util-base64": "3.208.0", + "@aws-sdk/util-body-length-browser": "3.188.0", + "@aws-sdk/util-body-length-node": "3.208.0", + "@aws-sdk/util-defaults-mode-browser": "3.234.0", + "@aws-sdk/util-defaults-mode-node": "3.234.0", + "@aws-sdk/util-endpoints": "3.245.0", + "@aws-sdk/util-retry": "3.229.0", + "@aws-sdk/util-user-agent-browser": "3.226.0", + "@aws-sdk/util-user-agent-node": "3.226.0", + "@aws-sdk/util-utf8-browser": "3.188.0", + "@aws-sdk/util-utf8-node": "3.208.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.245.0.tgz", + "integrity": "sha512-dxzRwRo55ZNQ4hQigC+cishxLSWlBrbr3iszG0FLviavLDOlnVG5UUxWpOIGvwr8pYiSfM4jnfMxiwYwiCLg1g==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "2.0.0", + "@aws-crypto/sha256-js": "2.0.0", + "@aws-sdk/config-resolver": "3.234.0", + "@aws-sdk/fetch-http-handler": "3.226.0", + "@aws-sdk/hash-node": "3.226.0", + "@aws-sdk/invalid-dependency": "3.226.0", + "@aws-sdk/middleware-content-length": "3.226.0", + "@aws-sdk/middleware-endpoint": "3.226.0", + "@aws-sdk/middleware-host-header": "3.226.0", + "@aws-sdk/middleware-logger": "3.226.0", + "@aws-sdk/middleware-recursion-detection": "3.226.0", + "@aws-sdk/middleware-retry": "3.235.0", + "@aws-sdk/middleware-serde": "3.226.0", + "@aws-sdk/middleware-stack": "3.226.0", + "@aws-sdk/middleware-user-agent": "3.226.0", + "@aws-sdk/node-config-provider": "3.226.0", + "@aws-sdk/node-http-handler": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/smithy-client": "3.234.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/url-parser": "3.226.0", + "@aws-sdk/util-base64": "3.208.0", + "@aws-sdk/util-body-length-browser": "3.188.0", + "@aws-sdk/util-body-length-node": "3.208.0", + "@aws-sdk/util-defaults-mode-browser": "3.234.0", + "@aws-sdk/util-defaults-mode-node": "3.234.0", + "@aws-sdk/util-endpoints": "3.245.0", + "@aws-sdk/util-retry": "3.229.0", + "@aws-sdk/util-user-agent-browser": "3.226.0", + "@aws-sdk/util-user-agent-node": "3.226.0", + "@aws-sdk/util-utf8-browser": "3.188.0", + "@aws-sdk/util-utf8-node": "3.208.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.245.0.tgz", + "integrity": "sha512-0pGPA00kEsu2Yq1Ul+OwftHxws5YVllm4iZrPtGnqmXr7wmf6B9lOtrMQF44y7Tfw53po6+bKz08OKTEWkkjUA==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "2.0.0", + "@aws-crypto/sha256-js": "2.0.0", + "@aws-sdk/config-resolver": "3.234.0", + "@aws-sdk/fetch-http-handler": "3.226.0", + "@aws-sdk/hash-node": "3.226.0", + "@aws-sdk/invalid-dependency": "3.226.0", + "@aws-sdk/middleware-content-length": "3.226.0", + "@aws-sdk/middleware-endpoint": "3.226.0", + "@aws-sdk/middleware-host-header": "3.226.0", + "@aws-sdk/middleware-logger": "3.226.0", + "@aws-sdk/middleware-recursion-detection": "3.226.0", + "@aws-sdk/middleware-retry": "3.235.0", + "@aws-sdk/middleware-serde": "3.226.0", + "@aws-sdk/middleware-stack": "3.226.0", + "@aws-sdk/middleware-user-agent": "3.226.0", + "@aws-sdk/node-config-provider": "3.226.0", + "@aws-sdk/node-http-handler": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/smithy-client": "3.234.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/url-parser": "3.226.0", + "@aws-sdk/util-base64": "3.208.0", + "@aws-sdk/util-body-length-browser": "3.188.0", + "@aws-sdk/util-body-length-node": "3.208.0", + "@aws-sdk/util-defaults-mode-browser": "3.234.0", + "@aws-sdk/util-defaults-mode-node": "3.234.0", + "@aws-sdk/util-endpoints": "3.245.0", + "@aws-sdk/util-retry": "3.229.0", + "@aws-sdk/util-user-agent-browser": "3.226.0", + "@aws-sdk/util-user-agent-node": "3.226.0", + "@aws-sdk/util-utf8-browser": "3.188.0", + "@aws-sdk/util-utf8-node": "3.208.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.245.0.tgz", + "integrity": "sha512-E+7v2sy34TLni/Dmz6bTU20NWvbHYH9sVUHKQ9kHhmFopUWrs4Nt77f85PbuiKJz/irjUh9ppT5q1odJNRKRVQ==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "2.0.0", + "@aws-crypto/sha256-js": "2.0.0", + "@aws-sdk/config-resolver": "3.234.0", + "@aws-sdk/credential-provider-node": "3.245.0", + "@aws-sdk/fetch-http-handler": "3.226.0", + "@aws-sdk/hash-node": "3.226.0", + "@aws-sdk/invalid-dependency": "3.226.0", + "@aws-sdk/middleware-content-length": "3.226.0", + "@aws-sdk/middleware-endpoint": "3.226.0", + "@aws-sdk/middleware-host-header": "3.226.0", + "@aws-sdk/middleware-logger": "3.226.0", + "@aws-sdk/middleware-recursion-detection": "3.226.0", + "@aws-sdk/middleware-retry": "3.235.0", + "@aws-sdk/middleware-sdk-sts": "3.226.0", + "@aws-sdk/middleware-serde": "3.226.0", + "@aws-sdk/middleware-signing": "3.226.0", + "@aws-sdk/middleware-stack": "3.226.0", + "@aws-sdk/middleware-user-agent": "3.226.0", + "@aws-sdk/node-config-provider": "3.226.0", + "@aws-sdk/node-http-handler": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/smithy-client": "3.234.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/url-parser": "3.226.0", + "@aws-sdk/util-base64": "3.208.0", + "@aws-sdk/util-body-length-browser": "3.188.0", + "@aws-sdk/util-body-length-node": "3.208.0", + "@aws-sdk/util-defaults-mode-browser": "3.234.0", + "@aws-sdk/util-defaults-mode-node": "3.234.0", + "@aws-sdk/util-endpoints": "3.245.0", + "@aws-sdk/util-retry": "3.229.0", + "@aws-sdk/util-user-agent-browser": "3.226.0", + "@aws-sdk/util-user-agent-node": "3.226.0", + "@aws-sdk/util-utf8-browser": "3.188.0", + "@aws-sdk/util-utf8-node": "3.208.0", + "fast-xml-parser": "4.0.11", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/config-resolver": { + "version": "3.234.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.234.0.tgz", + "integrity": "sha512-uZxy4wzllfvgCQxVc+Iqhde0NGAnfmV2hWR6ejadJaAFTuYNvQiRg9IqJy3pkyDPqXySiJ8Bom5PoJfgn55J/A==", + "optional": true, + "dependencies": { + "@aws-sdk/signature-v4": "3.226.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/util-config-provider": "3.208.0", + "@aws-sdk/util-middleware": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-cognito-identity": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.245.0.tgz", + "integrity": "sha512-DkiPv7Yb9iw3yAzvWUAkXrI23F1+kV8grdXzlSzob5suqv/dVON5pFXK9Siz62WwWsa2FeCEpgEF7RA0mrWLtA==", + "optional": true, + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.245.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.226.0.tgz", + "integrity": "sha512-sd8uK1ojbXxaZXlthzw/VXZwCPUtU3PjObOfr3Evj7MPIM2IH8h29foOlggx939MdLQGboJf9gKvLlvKDWtJRA==", + "optional": true, + "dependencies": { + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-imds": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.226.0.tgz", + "integrity": "sha512-//z/COQm2AjYFI1Lb0wKHTQSrvLFTyuKLFQGPJsKS7DPoxGOCKB7hmYerlbl01IDoCxTdyL//TyyPxbZEOQD5Q==", + "optional": true, + "dependencies": { + "@aws-sdk/node-config-provider": "3.226.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/url-parser": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.245.0.tgz", + "integrity": "sha512-1SjfVc5Wg0lLRUvwMrfjGgFkl+zfxn74gnkPr6by1QyMAoTzmeUkalPLAIqd+uHtFom9e3K633BQtX7zVPZ5XQ==", + "optional": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.226.0", + "@aws-sdk/credential-provider-imds": "3.226.0", + "@aws-sdk/credential-provider-process": "3.226.0", + "@aws-sdk/credential-provider-sso": "3.245.0", + "@aws-sdk/credential-provider-web-identity": "3.226.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/shared-ini-file-loader": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.245.0.tgz", + "integrity": "sha512-Dwv8zmRLTDLeEkGrK/sLNFZSC+ahXZxr07CuID054QKACIdUEvkqYlnalRiTeXngiHGQ54u8wU7f0D32R2oL0g==", + "optional": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.226.0", + "@aws-sdk/credential-provider-imds": "3.226.0", + "@aws-sdk/credential-provider-ini": "3.245.0", + "@aws-sdk/credential-provider-process": "3.226.0", + "@aws-sdk/credential-provider-sso": "3.245.0", + "@aws-sdk/credential-provider-web-identity": "3.226.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/shared-ini-file-loader": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.226.0.tgz", + "integrity": "sha512-iUDMdnrTvbvaCFhWwqyXrhvQ9+ojPqPqXhwZtY1X/Qaz+73S9gXBPJHZaZb2Ke0yKE1Ql3bJbKvmmxC/qLQMng==", + "optional": true, + "dependencies": { + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/shared-ini-file-loader": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.245.0.tgz", + "integrity": "sha512-txWrJc0WNBhXMi7q+twjx7cs/qzgTfbQ+vbag5idRmdoUeiR8rfLvihCab2NaGg50xhh+TaoUCXrgJp3E/XjYQ==", + "optional": true, + "dependencies": { + "@aws-sdk/client-sso": "3.245.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/shared-ini-file-loader": "3.226.0", + "@aws-sdk/token-providers": "3.245.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.226.0.tgz", + "integrity": "sha512-CCpv847rLB0SFOHz2igvUMFAzeT2fD3YnY4C8jltuJoEkn0ITn1Hlgt13nTJ5BUuvyti2mvyXZHmNzhMIMrIlw==", + "optional": true, + "dependencies": { + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.245.0.tgz", + "integrity": "sha512-6Uhsxk6MOuWplejhPJf7XDhegHmcZfj8hwnF4mXFJ6u4b2RxWPQCnqPcA0+VoAzIMUqbjqvkSzmVjQelGFtjNg==", + "optional": true, + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.245.0", + "@aws-sdk/client-sso": "3.245.0", + "@aws-sdk/client-sts": "3.245.0", + "@aws-sdk/credential-provider-cognito-identity": "3.245.0", + "@aws-sdk/credential-provider-env": "3.226.0", + "@aws-sdk/credential-provider-imds": "3.226.0", + "@aws-sdk/credential-provider-ini": "3.245.0", + "@aws-sdk/credential-provider-node": "3.245.0", + "@aws-sdk/credential-provider-process": "3.226.0", + "@aws-sdk/credential-provider-sso": "3.245.0", + "@aws-sdk/credential-provider-web-identity": "3.226.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/shared-ini-file-loader": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/fetch-http-handler": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.226.0.tgz", + "integrity": "sha512-JewZPMNEBXfi1xVnRa7pVtK/zgZD8/lQ/YnD8pq79WuMa2cwyhDtr8oqCoqsPW+WJT5ScXoMtuHxN78l8eKWgg==", + "optional": true, + "dependencies": { + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/querystring-builder": "3.226.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/util-base64": "3.208.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/hash-node": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.226.0.tgz", + "integrity": "sha512-MdlJhJ9/Espwd0+gUXdZRsHuostB2WxEVAszWxobP0FTT9PnicqnfK7ExmW+DUAc0ywxtEbR3e0UND65rlSTVw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.226.0", + "@aws-sdk/util-buffer-from": "3.208.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/invalid-dependency": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.226.0.tgz", + "integrity": "sha512-QXOYFmap8g9QzRjumcRCIo2GEZkdCwd7ePQW0OABWPhKHzlJ74vvBxywjU3s39EEBEluWXtZ7Iufg6GxZM4ifw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/is-array-buffer": { + "version": "3.201.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.201.0.tgz", + "integrity": "sha512-UPez5qLh3dNgt0DYnPD/q0mVJY84rA17QE26hVNOW3fAji8W2wrwrxdacWOxyXvlxWsVRcKmr+lay1MDqpAMfg==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-content-length": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.226.0.tgz", + "integrity": "sha512-ksUzlHJN2JMuyavjA46a4sctvnrnITqt2tbGGWWrAuXY1mel2j+VbgnmJUiwHKUO6bTFBBeft5Vd1TSOb4JmiA==", + "optional": true, + "dependencies": { + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-endpoint": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.226.0.tgz", + "integrity": "sha512-EvLFafjtUxTT0AC9p3aBQu1/fjhWdIeK58jIXaNFONfZ3F8QbEYUPuF/SqZvJM6cWfOO9qwYKkRDbCSTYhprIg==", + "optional": true, + "dependencies": { + "@aws-sdk/middleware-serde": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/signature-v4": "3.226.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/url-parser": "3.226.0", + "@aws-sdk/util-config-provider": "3.208.0", + "@aws-sdk/util-middleware": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.226.0.tgz", + "integrity": "sha512-haVkWVh6BUPwKgWwkL6sDvTkcZWvJjv8AgC8jiQuSl8GLZdzHTB8Qhi3IsfFta9HAuoLjxheWBE5Z/L0UrfhLA==", + "optional": true, + "dependencies": { + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.226.0.tgz", + "integrity": "sha512-m9gtLrrYnpN6yckcQ09rV7ExWOLMuq8mMPF/K3DbL/YL0TuILu9i2T1W+JuxSX+K9FMG2HrLAKivE/kMLr55xA==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.226.0.tgz", + "integrity": "sha512-mwRbdKEUeuNH5TEkyZ5FWxp6bL2UC1WbY+LDv6YjHxmSMKpAoOueEdtU34PqDOLrpXXxIGHDFmjeGeMfktyEcA==", + "optional": true, + "dependencies": { + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-retry": { + "version": "3.235.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.235.0.tgz", + "integrity": "sha512-50WHbJGpD3SNp9763MAlHqIhXil++JdQbKejNpHg7HsJne/ao3ub+fDOfx//mMBjpzBV25BGd5UlfL6blrClSg==", + "optional": true, + "dependencies": { + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/service-error-classification": "3.229.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/util-middleware": "3.226.0", + "@aws-sdk/util-retry": "3.229.0", + "tslib": "^2.3.1", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/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/@aws-sdk/middleware-sdk-sts": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.226.0.tgz", + "integrity": "sha512-NN9T/qoSD1kZvAT+VLny3NnlqgylYQcsgV3rvi/8lYzw/G/2s8VS6sm/VTWGGZhx08wZRv20MWzYu3bftcyqUg==", + "optional": true, + "dependencies": { + "@aws-sdk/middleware-signing": "3.226.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/signature-v4": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-serde": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.226.0.tgz", + "integrity": "sha512-nPuOOAkSfx9TxzdKFx0X2bDlinOxGrqD7iof926K/AEflxGD1DBdcaDdjlYlPDW2CVE8LV/rAgbYuLxh/E/1VA==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.226.0.tgz", + "integrity": "sha512-E6HmtPcl+IjYDDzi1xI2HpCbBq2avNWcjvCriMZWuTAtRVpnA6XDDGW5GY85IfS3A8G8vuWqEVPr8JcYUcjfew==", + "optional": true, + "dependencies": { + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/signature-v4": "3.226.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/util-middleware": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-stack": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.226.0.tgz", + "integrity": "sha512-85wF29LvPvpoed60fZGDYLwv1Zpd/cM0C22WSSFPw1SSJeqO4gtFYyCg2squfT3KI6kF43IIkOCJ+L7GtryPug==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.226.0.tgz", + "integrity": "sha512-N1WnfzCW1Y5yWhVAphf8OPGTe8Df3vmV7/LdsoQfmpkCZgLZeK2o0xITkUQhRj1mbw7yp8tVFLFV3R2lMurdAQ==", + "optional": true, + "dependencies": { + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/node-config-provider": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.226.0.tgz", + "integrity": "sha512-B8lQDqiRk7X5izFEUMXmi8CZLOKCTWQJU9HQf3ako+sF0gexo4nHN3jhoRWyLtcgC5S3on/2jxpAcqtm7kuY3w==", + "optional": true, + "dependencies": { + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/shared-ini-file-loader": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/node-http-handler": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.226.0.tgz", + "integrity": "sha512-xQCddnZNMiPmjr3W7HYM+f5ir4VfxgJh37eqZwX6EZmyItFpNNeVzKUgA920ka1VPz/ZUYB+2OFGiX3LCLkkaA==", + "optional": true, + "dependencies": { + "@aws-sdk/abort-controller": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/querystring-builder": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/property-provider": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.226.0.tgz", + "integrity": "sha512-TsljjG+Sg0LmdgfiAlWohluWKnxB/k8xenjeozZfzOr5bHmNHtdbWv6BtNvD/R83hw7SFXxbJHlD5H4u9p2NFg==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/protocol-http": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.226.0.tgz", + "integrity": "sha512-zWkVqiTA9RXL6y0hhfZc9bcU4DX2NI6Hw9IhQmSPeM59mdbPjJlY4bLlMr5YxywqO3yQ/ylNoAfrEzrDjlOSRg==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/querystring-builder": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.226.0.tgz", + "integrity": "sha512-LVurypuNeotO4lmirKXRC4NYrZRAyMJXuwO0f2a5ZAUJCjauwYrifKue6yCfU7bls7gut7nfcR6B99WBYpHs3g==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.226.0", + "@aws-sdk/util-uri-escape": "3.201.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/querystring-parser": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.226.0.tgz", + "integrity": "sha512-FzB+VrQ47KAFxiPt2YXrKZ8AOLZQqGTLCKHzx4bjxGmwgsjV8yIbtJiJhZLMcUQV4LtGeIY9ixIqQhGvnZHE4A==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/service-error-classification": { + "version": "3.229.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.229.0.tgz", + "integrity": "sha512-dnzWWQ0/NoWMUZ5C0DW3dPm0wC1O76Y/SpKbuJzWPkx1EYy6r8p32Ly4D9vUzrKDbRGf48YHIF2kOkBmu21CLg==", + "optional": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/shared-ini-file-loader": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.226.0.tgz", + "integrity": "sha512-661VQefsARxVyyV2FX9V61V+nNgImk7aN2hYlFKla6BCwZfMng+dEtD0xVGyg1PfRw0qvEv5LQyxMVgHcUSevA==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.226.0.tgz", + "integrity": "sha512-/R5q5agdPd7HJB68XMzpxrNPk158EHUvkFkuRu5Qf3kkkHebEzWEBlWoVpUe6ss4rP9Tqcue6xPuaftEmhjpYw==", + "optional": true, + "dependencies": { + "@aws-sdk/is-array-buffer": "3.201.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/util-hex-encoding": "3.201.0", + "@aws-sdk/util-middleware": "3.226.0", + "@aws-sdk/util-uri-escape": "3.201.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/smithy-client": { + "version": "3.234.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.234.0.tgz", + "integrity": "sha512-8AtR/k4vsFvjXeQbIzq/Wy7Nbk48Ou0wUEeVYPHWHPSU8QamFWORkOwmKtKMfHAyZvmqiAPeQqHFkq+UJhWyyQ==", + "optional": true, + "dependencies": { + "@aws-sdk/middleware-stack": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.245.0.tgz", + "integrity": "sha512-m/spXR/vEXGb+zMqRUMQYVMwFZSTdK5RkddYqamYkNhIoLm60EYeRu57JsMMs5djKi8dBRSKiXwVHx0l2rXMjg==", + "optional": true, + "dependencies": { + "@aws-sdk/client-sso-oidc": "3.245.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/shared-ini-file-loader": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.226.0.tgz", + "integrity": "sha512-MmmNHrWeO4man7wpOwrAhXlevqtOV9ZLcH4RhnG5LmRce0RFOApx24HoKENfFCcOyCm5LQBlsXCqi0dZWDWU0A==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/url-parser": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.226.0.tgz", + "integrity": "sha512-p5RLE0QWyP0OcTOLmFcLdVgUcUEzmEfmdrnOxyNzomcYb0p3vUagA5zfa1HVK2azsQJFBv28GfvMnba9bGhObg==", + "optional": true, + "dependencies": { + "@aws-sdk/querystring-parser": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/util-base64": { + "version": "3.208.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.208.0.tgz", + "integrity": "sha512-PQniZph5A6N7uuEOQi+1hnMz/FSOK/8kMFyFO+4DgA1dZ5pcKcn5wiFwHkcTb/BsgVqQa3Jx0VHNnvhlS8JyTg==", + "optional": true, + "dependencies": { + "@aws-sdk/util-buffer-from": "3.208.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-body-length-browser": { + "version": "3.188.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.188.0.tgz", + "integrity": "sha512-8VpnwFWXhnZ/iRSl9mTf+VKOX9wDE8QtN4bj9pBfxwf90H1X7E8T6NkiZD3k+HubYf2J94e7DbeHs7fuCPW5Qg==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/util-body-length-node": { + "version": "3.208.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.208.0.tgz", + "integrity": "sha512-3zj50e5g7t/MQf53SsuuSf0hEELzMtD8RX8C76f12OSRo2Bca4FLLYHe0TZbxcfQHom8/hOaeZEyTyMogMglqg==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-buffer-from": { + "version": "3.208.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.208.0.tgz", + "integrity": "sha512-7L0XUixNEFcLUGPeBF35enCvB9Xl+K6SQsmbrPk1P3mlV9mguWSDQqbOBwY1Ir0OVbD6H/ZOQU7hI/9RtRI0Zw==", + "optional": true, + "dependencies": { + "@aws-sdk/is-array-buffer": "3.201.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-config-provider": { + "version": "3.208.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.208.0.tgz", + "integrity": "sha512-DSRqwrERUsT34ug+anlMBIFooBEGwM8GejC7q00Y/9IPrQy50KnG5PW2NiTjuLKNi7pdEOlwTSEocJE15eDZIg==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-defaults-mode-browser": { + "version": "3.234.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.234.0.tgz", + "integrity": "sha512-IHMKXjTbOD8XMz5+2oCOsVP94BYb9YyjXdns0aAXr2NAo7k2+RCzXQ2DebJXppGda1F6opFutoKwyVSN0cmbMw==", + "optional": true, + "dependencies": { + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/types": "3.226.0", + "bowser": "^2.11.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/util-defaults-mode-node": { + "version": "3.234.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.234.0.tgz", + "integrity": "sha512-UGjQ+OjBYYhxFVtUY+jtr0ZZgzZh6OHtYwRhFt8IHewJXFCfZTyfsbX20szBj5y1S4HRIUJ7cwBLIytTqMbI5w==", + "optional": true, + "dependencies": { + "@aws-sdk/config-resolver": "3.234.0", + "@aws-sdk/credential-provider-imds": "3.226.0", + "@aws-sdk/node-config-provider": "3.226.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.245.0.tgz", + "integrity": "sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-hex-encoding": { + "version": "3.201.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.201.0.tgz", + "integrity": "sha512-7t1vR1pVxKx0motd3X9rI3m/xNp78p3sHtP5yo4NP4ARpxyJ0fokBomY8ScaH2D/B+U5o9ARxldJUdMqyBlJcA==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.208.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.208.0.tgz", + "integrity": "sha512-iua1A2+P7JJEDHVgvXrRJSvsnzG7stYSGQnBVphIUlemwl6nN5D+QrgbjECtrbxRz8asYFHSzhdhECqN+tFiBg==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-middleware": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.226.0.tgz", + "integrity": "sha512-B96CQnwX4gRvQdaQkdUtqvDPkrptV5+va6FVeJOocU/DbSYMAScLxtR3peMS8cnlOT6nL1Eoa42OI9AfZz1VwQ==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-retry": { + "version": "3.229.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.229.0.tgz", + "integrity": "sha512-0zKTqi0P1inD0LzIMuXRIYYQ/8c1lWMg/cfiqUcIAF1TpatlpZuN7umU0ierpBFud7S+zDgg0oemh+Nj8xliJw==", + "optional": true, + "dependencies": { + "@aws-sdk/service-error-classification": "3.229.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@aws-sdk/util-uri-escape": { + "version": "3.201.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.201.0.tgz", + "integrity": "sha512-TeTWbGx4LU2c5rx0obHeDFeO9HvwYwQtMh1yniBz00pQb6Qt6YVOETVQikRZ+XRQwEyCg/dA375UplIpiy54mA==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.226.0.tgz", + "integrity": "sha512-PhBIu2h6sPJPcv2I7ELfFizdl5pNiL4LfxrasMCYXQkJvVnoXztHA1x+CQbXIdtZOIlpjC+6BjDcE0uhnpvfcA==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.226.0", + "bowser": "^2.11.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.226.0.tgz", + "integrity": "sha512-othPc5Dz/pkYkxH+nZPhc1Al0HndQT8zHD4e9h+EZ+8lkd8n+IsnLfTS/mSJWrfiC6UlNRVw55cItstmJyMe/A==", + "optional": true, + "dependencies": { + "@aws-sdk/node-config-provider": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + }, + "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.188.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.188.0.tgz", + "integrity": "sha512-jt627x0+jE+Ydr9NwkFstg3cUvgWh56qdaqAMDsqgRlKD21md/6G226z/Qxl7lb1VEW2LlmCx43ai/37Qwcj2Q==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/util-utf8-node": { + "version": "3.208.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-node/-/util-utf8-node-3.208.0.tgz", + "integrity": "sha512-jKY87Acv0yWBdFxx6bveagy5FYjz+dtV8IPT7ay1E2WPWH1czoIdMAkc8tSInK31T6CRnHWkLZ1qYwCbgRfERQ==", + "optional": true, + "dependencies": { + "@aws-sdk/util-buffer-from": "3.208.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -342,8 +1418,7 @@ "node_modules/@types/node": { "version": "18.11.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", - "dev": true + "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" }, "node_modules/@types/qs": { "version": "6.9.7", @@ -377,6 +1452,20 @@ "minipass": "^3.3.5" } }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + }, + "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/@types/yargs": { "version": "17.0.19", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", @@ -586,6 +1675,46 @@ "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/bson": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.1.tgz", + "integrity": "sha512-XkuFtlCzi0WSy8D6PMhvrQ/q8VlZHN/2bJ/shJglwuA6TPD2ZP/hHLB7iDxOEWVINHN/UVTxP4pqZqOKMXPIXg==", + "dependencies": { + "buffer": "^5.6.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -1049,6 +2178,22 @@ "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==" }, + "node_modules/fast-xml-parser": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.0.11.tgz", + "integrity": "sha512-4aUg3aNRR/WjQAcpceODG1C3x3lFANXRo8+1biqfieHmg9pyMt7qB4lQV/Ta6sJCTbA5vfD8fnA8S54JATiFUA==", + "optional": true, + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + }, "node_modules/finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -1389,11 +2534,35 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/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", @@ -1591,6 +2760,12 @@ "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", @@ -1684,6 +2859,32 @@ "node": ">=10" } }, + "node_modules/mongodb": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.13.0.tgz", + "integrity": "sha512-+taZ/bV8d1pYuHL4U+gSwkhmDrwkWbH1l4aah4YpmpscMwgFBkufIKxgP/G7m87/NUuQzc2Z75ZTI7ZOyqZLbw==", + "dependencies": { + "bson": "^4.7.0", + "mongodb-connection-string-url": "^2.5.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">=12.9.0" + }, + "optionalDependencies": { + "@aws-sdk/credential-providers": "^3.186.0", + "saslprep": "^1.0.3" + } + }, + "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/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -2014,6 +3215,18 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/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, + "dependencies": { + "sparse-bitfield": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", @@ -2098,6 +3311,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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", @@ -2107,6 +3342,15 @@ "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/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -2147,6 +3391,12 @@ "node": ">=8" } }, + "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/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -2255,6 +3505,12 @@ } } }, + "node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "optional": true + }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -2568,6 +3824,920 @@ "tunnel": "^0.0.6" } }, + "@aws-crypto/ie11-detection": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-2.0.2.tgz", + "integrity": "sha512-5XDMQY98gMAf/WRTic5G++jfmS/VLM0rwpiOpaainKi4L0nqWMSB1SzsrEG5rjFZGYN6ZAefO+/Yta2dFM0kMw==", + "optional": true, + "requires": { + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + } + } + }, + "@aws-crypto/sha256-browser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-2.0.0.tgz", + "integrity": "sha512-rYXOQ8BFOaqMEHJrLHul/25ckWH6GTJtdLSajhlqGMx0PmSueAuvboCuZCTqEKlxR8CQOwRarxYMZZSYlhRA1A==", + "optional": true, + "requires": { + "@aws-crypto/ie11-detection": "^2.0.0", + "@aws-crypto/sha256-js": "^2.0.0", + "@aws-crypto/supports-web-crypto": "^2.0.0", + "@aws-crypto/util": "^2.0.0", + "@aws-sdk/types": "^3.1.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + } + } + }, + "@aws-crypto/sha256-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-2.0.0.tgz", + "integrity": "sha512-VZY+mCY4Nmrs5WGfitmNqXzaE873fcIZDu54cbaDaaamsaTOP1DBImV9F4pICc3EHjQXujyE8jig+PFCaew9ig==", + "optional": true, + "requires": { + "@aws-crypto/util": "^2.0.0", + "@aws-sdk/types": "^3.1.0", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + } + } + }, + "@aws-crypto/supports-web-crypto": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-2.0.2.tgz", + "integrity": "sha512-6mbSsLHwZ99CTOOswvCRP3C+VCWnzBf+1SnbWxzzJ9lR0mA0JnY2JEAhp8rqmTE0GPFy88rrM27ffgp62oErMQ==", + "optional": true, + "requires": { + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + } + } + }, + "@aws-crypto/util": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-2.0.2.tgz", + "integrity": "sha512-Lgu5v/0e/BcrZ5m/IWqzPUf3UYFTy/PpeED+uc9SWUR1iZQL8XXbGQg10UfllwwBryO3hFF5dizK+78aoXC1eA==", + "optional": true, + "requires": { + "@aws-sdk/types": "^3.110.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + } + } + }, + "@aws-sdk/abort-controller": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.226.0.tgz", + "integrity": "sha512-cJVzr1xxPBd08voknXvR0RLgtZKGKt6WyDpH/BaPCu3rfSqWCDZKzwqe940eqosjmKrxC6pUZNKASIqHOQ8xxQ==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/client-cognito-identity": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.245.0.tgz", + "integrity": "sha512-c5briTS05rAioO5b84bVng9M1KyAXcxJtDHeuoeAAZBuU+Dd0Scg3vyXyAFlGI+TsNyxqHAqqRdAoG4WNxJo/Q==", + "optional": true, + "requires": { + "@aws-crypto/sha256-browser": "2.0.0", + "@aws-crypto/sha256-js": "2.0.0", + "@aws-sdk/client-sts": "3.245.0", + "@aws-sdk/config-resolver": "3.234.0", + "@aws-sdk/credential-provider-node": "3.245.0", + "@aws-sdk/fetch-http-handler": "3.226.0", + "@aws-sdk/hash-node": "3.226.0", + "@aws-sdk/invalid-dependency": "3.226.0", + "@aws-sdk/middleware-content-length": "3.226.0", + "@aws-sdk/middleware-endpoint": "3.226.0", + "@aws-sdk/middleware-host-header": "3.226.0", + "@aws-sdk/middleware-logger": "3.226.0", + "@aws-sdk/middleware-recursion-detection": "3.226.0", + "@aws-sdk/middleware-retry": "3.235.0", + "@aws-sdk/middleware-serde": "3.226.0", + "@aws-sdk/middleware-signing": "3.226.0", + "@aws-sdk/middleware-stack": "3.226.0", + "@aws-sdk/middleware-user-agent": "3.226.0", + "@aws-sdk/node-config-provider": "3.226.0", + "@aws-sdk/node-http-handler": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/smithy-client": "3.234.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/url-parser": "3.226.0", + "@aws-sdk/util-base64": "3.208.0", + "@aws-sdk/util-body-length-browser": "3.188.0", + "@aws-sdk/util-body-length-node": "3.208.0", + "@aws-sdk/util-defaults-mode-browser": "3.234.0", + "@aws-sdk/util-defaults-mode-node": "3.234.0", + "@aws-sdk/util-endpoints": "3.245.0", + "@aws-sdk/util-retry": "3.229.0", + "@aws-sdk/util-user-agent-browser": "3.226.0", + "@aws-sdk/util-user-agent-node": "3.226.0", + "@aws-sdk/util-utf8-browser": "3.188.0", + "@aws-sdk/util-utf8-node": "3.208.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/client-sso": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.245.0.tgz", + "integrity": "sha512-dxzRwRo55ZNQ4hQigC+cishxLSWlBrbr3iszG0FLviavLDOlnVG5UUxWpOIGvwr8pYiSfM4jnfMxiwYwiCLg1g==", + "optional": true, + "requires": { + "@aws-crypto/sha256-browser": "2.0.0", + "@aws-crypto/sha256-js": "2.0.0", + "@aws-sdk/config-resolver": "3.234.0", + "@aws-sdk/fetch-http-handler": "3.226.0", + "@aws-sdk/hash-node": "3.226.0", + "@aws-sdk/invalid-dependency": "3.226.0", + "@aws-sdk/middleware-content-length": "3.226.0", + "@aws-sdk/middleware-endpoint": "3.226.0", + "@aws-sdk/middleware-host-header": "3.226.0", + "@aws-sdk/middleware-logger": "3.226.0", + "@aws-sdk/middleware-recursion-detection": "3.226.0", + "@aws-sdk/middleware-retry": "3.235.0", + "@aws-sdk/middleware-serde": "3.226.0", + "@aws-sdk/middleware-stack": "3.226.0", + "@aws-sdk/middleware-user-agent": "3.226.0", + "@aws-sdk/node-config-provider": "3.226.0", + "@aws-sdk/node-http-handler": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/smithy-client": "3.234.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/url-parser": "3.226.0", + "@aws-sdk/util-base64": "3.208.0", + "@aws-sdk/util-body-length-browser": "3.188.0", + "@aws-sdk/util-body-length-node": "3.208.0", + "@aws-sdk/util-defaults-mode-browser": "3.234.0", + "@aws-sdk/util-defaults-mode-node": "3.234.0", + "@aws-sdk/util-endpoints": "3.245.0", + "@aws-sdk/util-retry": "3.229.0", + "@aws-sdk/util-user-agent-browser": "3.226.0", + "@aws-sdk/util-user-agent-node": "3.226.0", + "@aws-sdk/util-utf8-browser": "3.188.0", + "@aws-sdk/util-utf8-node": "3.208.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/client-sso-oidc": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.245.0.tgz", + "integrity": "sha512-0pGPA00kEsu2Yq1Ul+OwftHxws5YVllm4iZrPtGnqmXr7wmf6B9lOtrMQF44y7Tfw53po6+bKz08OKTEWkkjUA==", + "optional": true, + "requires": { + "@aws-crypto/sha256-browser": "2.0.0", + "@aws-crypto/sha256-js": "2.0.0", + "@aws-sdk/config-resolver": "3.234.0", + "@aws-sdk/fetch-http-handler": "3.226.0", + "@aws-sdk/hash-node": "3.226.0", + "@aws-sdk/invalid-dependency": "3.226.0", + "@aws-sdk/middleware-content-length": "3.226.0", + "@aws-sdk/middleware-endpoint": "3.226.0", + "@aws-sdk/middleware-host-header": "3.226.0", + "@aws-sdk/middleware-logger": "3.226.0", + "@aws-sdk/middleware-recursion-detection": "3.226.0", + "@aws-sdk/middleware-retry": "3.235.0", + "@aws-sdk/middleware-serde": "3.226.0", + "@aws-sdk/middleware-stack": "3.226.0", + "@aws-sdk/middleware-user-agent": "3.226.0", + "@aws-sdk/node-config-provider": "3.226.0", + "@aws-sdk/node-http-handler": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/smithy-client": "3.234.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/url-parser": "3.226.0", + "@aws-sdk/util-base64": "3.208.0", + "@aws-sdk/util-body-length-browser": "3.188.0", + "@aws-sdk/util-body-length-node": "3.208.0", + "@aws-sdk/util-defaults-mode-browser": "3.234.0", + "@aws-sdk/util-defaults-mode-node": "3.234.0", + "@aws-sdk/util-endpoints": "3.245.0", + "@aws-sdk/util-retry": "3.229.0", + "@aws-sdk/util-user-agent-browser": "3.226.0", + "@aws-sdk/util-user-agent-node": "3.226.0", + "@aws-sdk/util-utf8-browser": "3.188.0", + "@aws-sdk/util-utf8-node": "3.208.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/client-sts": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.245.0.tgz", + "integrity": "sha512-E+7v2sy34TLni/Dmz6bTU20NWvbHYH9sVUHKQ9kHhmFopUWrs4Nt77f85PbuiKJz/irjUh9ppT5q1odJNRKRVQ==", + "optional": true, + "requires": { + "@aws-crypto/sha256-browser": "2.0.0", + "@aws-crypto/sha256-js": "2.0.0", + "@aws-sdk/config-resolver": "3.234.0", + "@aws-sdk/credential-provider-node": "3.245.0", + "@aws-sdk/fetch-http-handler": "3.226.0", + "@aws-sdk/hash-node": "3.226.0", + "@aws-sdk/invalid-dependency": "3.226.0", + "@aws-sdk/middleware-content-length": "3.226.0", + "@aws-sdk/middleware-endpoint": "3.226.0", + "@aws-sdk/middleware-host-header": "3.226.0", + "@aws-sdk/middleware-logger": "3.226.0", + "@aws-sdk/middleware-recursion-detection": "3.226.0", + "@aws-sdk/middleware-retry": "3.235.0", + "@aws-sdk/middleware-sdk-sts": "3.226.0", + "@aws-sdk/middleware-serde": "3.226.0", + "@aws-sdk/middleware-signing": "3.226.0", + "@aws-sdk/middleware-stack": "3.226.0", + "@aws-sdk/middleware-user-agent": "3.226.0", + "@aws-sdk/node-config-provider": "3.226.0", + "@aws-sdk/node-http-handler": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/smithy-client": "3.234.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/url-parser": "3.226.0", + "@aws-sdk/util-base64": "3.208.0", + "@aws-sdk/util-body-length-browser": "3.188.0", + "@aws-sdk/util-body-length-node": "3.208.0", + "@aws-sdk/util-defaults-mode-browser": "3.234.0", + "@aws-sdk/util-defaults-mode-node": "3.234.0", + "@aws-sdk/util-endpoints": "3.245.0", + "@aws-sdk/util-retry": "3.229.0", + "@aws-sdk/util-user-agent-browser": "3.226.0", + "@aws-sdk/util-user-agent-node": "3.226.0", + "@aws-sdk/util-utf8-browser": "3.188.0", + "@aws-sdk/util-utf8-node": "3.208.0", + "fast-xml-parser": "4.0.11", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/config-resolver": { + "version": "3.234.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.234.0.tgz", + "integrity": "sha512-uZxy4wzllfvgCQxVc+Iqhde0NGAnfmV2hWR6ejadJaAFTuYNvQiRg9IqJy3pkyDPqXySiJ8Bom5PoJfgn55J/A==", + "optional": true, + "requires": { + "@aws-sdk/signature-v4": "3.226.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/util-config-provider": "3.208.0", + "@aws-sdk/util-middleware": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/credential-provider-cognito-identity": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.245.0.tgz", + "integrity": "sha512-DkiPv7Yb9iw3yAzvWUAkXrI23F1+kV8grdXzlSzob5suqv/dVON5pFXK9Siz62WwWsa2FeCEpgEF7RA0mrWLtA==", + "optional": true, + "requires": { + "@aws-sdk/client-cognito-identity": "3.245.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/credential-provider-env": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.226.0.tgz", + "integrity": "sha512-sd8uK1ojbXxaZXlthzw/VXZwCPUtU3PjObOfr3Evj7MPIM2IH8h29foOlggx939MdLQGboJf9gKvLlvKDWtJRA==", + "optional": true, + "requires": { + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/credential-provider-imds": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.226.0.tgz", + "integrity": "sha512-//z/COQm2AjYFI1Lb0wKHTQSrvLFTyuKLFQGPJsKS7DPoxGOCKB7hmYerlbl01IDoCxTdyL//TyyPxbZEOQD5Q==", + "optional": true, + "requires": { + "@aws-sdk/node-config-provider": "3.226.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/url-parser": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/credential-provider-ini": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.245.0.tgz", + "integrity": "sha512-1SjfVc5Wg0lLRUvwMrfjGgFkl+zfxn74gnkPr6by1QyMAoTzmeUkalPLAIqd+uHtFom9e3K633BQtX7zVPZ5XQ==", + "optional": true, + "requires": { + "@aws-sdk/credential-provider-env": "3.226.0", + "@aws-sdk/credential-provider-imds": "3.226.0", + "@aws-sdk/credential-provider-process": "3.226.0", + "@aws-sdk/credential-provider-sso": "3.245.0", + "@aws-sdk/credential-provider-web-identity": "3.226.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/shared-ini-file-loader": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/credential-provider-node": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.245.0.tgz", + "integrity": "sha512-Dwv8zmRLTDLeEkGrK/sLNFZSC+ahXZxr07CuID054QKACIdUEvkqYlnalRiTeXngiHGQ54u8wU7f0D32R2oL0g==", + "optional": true, + "requires": { + "@aws-sdk/credential-provider-env": "3.226.0", + "@aws-sdk/credential-provider-imds": "3.226.0", + "@aws-sdk/credential-provider-ini": "3.245.0", + "@aws-sdk/credential-provider-process": "3.226.0", + "@aws-sdk/credential-provider-sso": "3.245.0", + "@aws-sdk/credential-provider-web-identity": "3.226.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/shared-ini-file-loader": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/credential-provider-process": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.226.0.tgz", + "integrity": "sha512-iUDMdnrTvbvaCFhWwqyXrhvQ9+ojPqPqXhwZtY1X/Qaz+73S9gXBPJHZaZb2Ke0yKE1Ql3bJbKvmmxC/qLQMng==", + "optional": true, + "requires": { + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/shared-ini-file-loader": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/credential-provider-sso": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.245.0.tgz", + "integrity": "sha512-txWrJc0WNBhXMi7q+twjx7cs/qzgTfbQ+vbag5idRmdoUeiR8rfLvihCab2NaGg50xhh+TaoUCXrgJp3E/XjYQ==", + "optional": true, + "requires": { + "@aws-sdk/client-sso": "3.245.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/shared-ini-file-loader": "3.226.0", + "@aws-sdk/token-providers": "3.245.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/credential-provider-web-identity": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.226.0.tgz", + "integrity": "sha512-CCpv847rLB0SFOHz2igvUMFAzeT2fD3YnY4C8jltuJoEkn0ITn1Hlgt13nTJ5BUuvyti2mvyXZHmNzhMIMrIlw==", + "optional": true, + "requires": { + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/credential-providers": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.245.0.tgz", + "integrity": "sha512-6Uhsxk6MOuWplejhPJf7XDhegHmcZfj8hwnF4mXFJ6u4b2RxWPQCnqPcA0+VoAzIMUqbjqvkSzmVjQelGFtjNg==", + "optional": true, + "requires": { + "@aws-sdk/client-cognito-identity": "3.245.0", + "@aws-sdk/client-sso": "3.245.0", + "@aws-sdk/client-sts": "3.245.0", + "@aws-sdk/credential-provider-cognito-identity": "3.245.0", + "@aws-sdk/credential-provider-env": "3.226.0", + "@aws-sdk/credential-provider-imds": "3.226.0", + "@aws-sdk/credential-provider-ini": "3.245.0", + "@aws-sdk/credential-provider-node": "3.245.0", + "@aws-sdk/credential-provider-process": "3.226.0", + "@aws-sdk/credential-provider-sso": "3.245.0", + "@aws-sdk/credential-provider-web-identity": "3.226.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/shared-ini-file-loader": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/fetch-http-handler": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.226.0.tgz", + "integrity": "sha512-JewZPMNEBXfi1xVnRa7pVtK/zgZD8/lQ/YnD8pq79WuMa2cwyhDtr8oqCoqsPW+WJT5ScXoMtuHxN78l8eKWgg==", + "optional": true, + "requires": { + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/querystring-builder": "3.226.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/util-base64": "3.208.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/hash-node": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.226.0.tgz", + "integrity": "sha512-MdlJhJ9/Espwd0+gUXdZRsHuostB2WxEVAszWxobP0FTT9PnicqnfK7ExmW+DUAc0ywxtEbR3e0UND65rlSTVw==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.226.0", + "@aws-sdk/util-buffer-from": "3.208.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/invalid-dependency": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.226.0.tgz", + "integrity": "sha512-QXOYFmap8g9QzRjumcRCIo2GEZkdCwd7ePQW0OABWPhKHzlJ74vvBxywjU3s39EEBEluWXtZ7Iufg6GxZM4ifw==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/is-array-buffer": { + "version": "3.201.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.201.0.tgz", + "integrity": "sha512-UPez5qLh3dNgt0DYnPD/q0mVJY84rA17QE26hVNOW3fAji8W2wrwrxdacWOxyXvlxWsVRcKmr+lay1MDqpAMfg==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + } + }, + "@aws-sdk/middleware-content-length": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.226.0.tgz", + "integrity": "sha512-ksUzlHJN2JMuyavjA46a4sctvnrnITqt2tbGGWWrAuXY1mel2j+VbgnmJUiwHKUO6bTFBBeft5Vd1TSOb4JmiA==", + "optional": true, + "requires": { + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/middleware-endpoint": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.226.0.tgz", + "integrity": "sha512-EvLFafjtUxTT0AC9p3aBQu1/fjhWdIeK58jIXaNFONfZ3F8QbEYUPuF/SqZvJM6cWfOO9qwYKkRDbCSTYhprIg==", + "optional": true, + "requires": { + "@aws-sdk/middleware-serde": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/signature-v4": "3.226.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/url-parser": "3.226.0", + "@aws-sdk/util-config-provider": "3.208.0", + "@aws-sdk/util-middleware": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/middleware-host-header": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.226.0.tgz", + "integrity": "sha512-haVkWVh6BUPwKgWwkL6sDvTkcZWvJjv8AgC8jiQuSl8GLZdzHTB8Qhi3IsfFta9HAuoLjxheWBE5Z/L0UrfhLA==", + "optional": true, + "requires": { + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/middleware-logger": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.226.0.tgz", + "integrity": "sha512-m9gtLrrYnpN6yckcQ09rV7ExWOLMuq8mMPF/K3DbL/YL0TuILu9i2T1W+JuxSX+K9FMG2HrLAKivE/kMLr55xA==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/middleware-recursion-detection": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.226.0.tgz", + "integrity": "sha512-mwRbdKEUeuNH5TEkyZ5FWxp6bL2UC1WbY+LDv6YjHxmSMKpAoOueEdtU34PqDOLrpXXxIGHDFmjeGeMfktyEcA==", + "optional": true, + "requires": { + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/middleware-retry": { + "version": "3.235.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.235.0.tgz", + "integrity": "sha512-50WHbJGpD3SNp9763MAlHqIhXil++JdQbKejNpHg7HsJne/ao3ub+fDOfx//mMBjpzBV25BGd5UlfL6blrClSg==", + "optional": true, + "requires": { + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/service-error-classification": "3.229.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/util-middleware": "3.226.0", + "@aws-sdk/util-retry": "3.229.0", + "tslib": "^2.3.1", + "uuid": "^8.3.2" + }, + "dependencies": { + "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 + } + } + }, + "@aws-sdk/middleware-sdk-sts": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.226.0.tgz", + "integrity": "sha512-NN9T/qoSD1kZvAT+VLny3NnlqgylYQcsgV3rvi/8lYzw/G/2s8VS6sm/VTWGGZhx08wZRv20MWzYu3bftcyqUg==", + "optional": true, + "requires": { + "@aws-sdk/middleware-signing": "3.226.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/signature-v4": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/middleware-serde": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.226.0.tgz", + "integrity": "sha512-nPuOOAkSfx9TxzdKFx0X2bDlinOxGrqD7iof926K/AEflxGD1DBdcaDdjlYlPDW2CVE8LV/rAgbYuLxh/E/1VA==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/middleware-signing": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.226.0.tgz", + "integrity": "sha512-E6HmtPcl+IjYDDzi1xI2HpCbBq2avNWcjvCriMZWuTAtRVpnA6XDDGW5GY85IfS3A8G8vuWqEVPr8JcYUcjfew==", + "optional": true, + "requires": { + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/signature-v4": "3.226.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/util-middleware": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/middleware-stack": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.226.0.tgz", + "integrity": "sha512-85wF29LvPvpoed60fZGDYLwv1Zpd/cM0C22WSSFPw1SSJeqO4gtFYyCg2squfT3KI6kF43IIkOCJ+L7GtryPug==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + } + }, + "@aws-sdk/middleware-user-agent": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.226.0.tgz", + "integrity": "sha512-N1WnfzCW1Y5yWhVAphf8OPGTe8Df3vmV7/LdsoQfmpkCZgLZeK2o0xITkUQhRj1mbw7yp8tVFLFV3R2lMurdAQ==", + "optional": true, + "requires": { + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/node-config-provider": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.226.0.tgz", + "integrity": "sha512-B8lQDqiRk7X5izFEUMXmi8CZLOKCTWQJU9HQf3ako+sF0gexo4nHN3jhoRWyLtcgC5S3on/2jxpAcqtm7kuY3w==", + "optional": true, + "requires": { + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/shared-ini-file-loader": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/node-http-handler": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.226.0.tgz", + "integrity": "sha512-xQCddnZNMiPmjr3W7HYM+f5ir4VfxgJh37eqZwX6EZmyItFpNNeVzKUgA920ka1VPz/ZUYB+2OFGiX3LCLkkaA==", + "optional": true, + "requires": { + "@aws-sdk/abort-controller": "3.226.0", + "@aws-sdk/protocol-http": "3.226.0", + "@aws-sdk/querystring-builder": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/property-provider": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.226.0.tgz", + "integrity": "sha512-TsljjG+Sg0LmdgfiAlWohluWKnxB/k8xenjeozZfzOr5bHmNHtdbWv6BtNvD/R83hw7SFXxbJHlD5H4u9p2NFg==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/protocol-http": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.226.0.tgz", + "integrity": "sha512-zWkVqiTA9RXL6y0hhfZc9bcU4DX2NI6Hw9IhQmSPeM59mdbPjJlY4bLlMr5YxywqO3yQ/ylNoAfrEzrDjlOSRg==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/querystring-builder": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.226.0.tgz", + "integrity": "sha512-LVurypuNeotO4lmirKXRC4NYrZRAyMJXuwO0f2a5ZAUJCjauwYrifKue6yCfU7bls7gut7nfcR6B99WBYpHs3g==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.226.0", + "@aws-sdk/util-uri-escape": "3.201.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/querystring-parser": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.226.0.tgz", + "integrity": "sha512-FzB+VrQ47KAFxiPt2YXrKZ8AOLZQqGTLCKHzx4bjxGmwgsjV8yIbtJiJhZLMcUQV4LtGeIY9ixIqQhGvnZHE4A==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/service-error-classification": { + "version": "3.229.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.229.0.tgz", + "integrity": "sha512-dnzWWQ0/NoWMUZ5C0DW3dPm0wC1O76Y/SpKbuJzWPkx1EYy6r8p32Ly4D9vUzrKDbRGf48YHIF2kOkBmu21CLg==", + "optional": true + }, + "@aws-sdk/shared-ini-file-loader": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.226.0.tgz", + "integrity": "sha512-661VQefsARxVyyV2FX9V61V+nNgImk7aN2hYlFKla6BCwZfMng+dEtD0xVGyg1PfRw0qvEv5LQyxMVgHcUSevA==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/signature-v4": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.226.0.tgz", + "integrity": "sha512-/R5q5agdPd7HJB68XMzpxrNPk158EHUvkFkuRu5Qf3kkkHebEzWEBlWoVpUe6ss4rP9Tqcue6xPuaftEmhjpYw==", + "optional": true, + "requires": { + "@aws-sdk/is-array-buffer": "3.201.0", + "@aws-sdk/types": "3.226.0", + "@aws-sdk/util-hex-encoding": "3.201.0", + "@aws-sdk/util-middleware": "3.226.0", + "@aws-sdk/util-uri-escape": "3.201.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/smithy-client": { + "version": "3.234.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.234.0.tgz", + "integrity": "sha512-8AtR/k4vsFvjXeQbIzq/Wy7Nbk48Ou0wUEeVYPHWHPSU8QamFWORkOwmKtKMfHAyZvmqiAPeQqHFkq+UJhWyyQ==", + "optional": true, + "requires": { + "@aws-sdk/middleware-stack": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/token-providers": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.245.0.tgz", + "integrity": "sha512-m/spXR/vEXGb+zMqRUMQYVMwFZSTdK5RkddYqamYkNhIoLm60EYeRu57JsMMs5djKi8dBRSKiXwVHx0l2rXMjg==", + "optional": true, + "requires": { + "@aws-sdk/client-sso-oidc": "3.245.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/shared-ini-file-loader": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/types": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.226.0.tgz", + "integrity": "sha512-MmmNHrWeO4man7wpOwrAhXlevqtOV9ZLcH4RhnG5LmRce0RFOApx24HoKENfFCcOyCm5LQBlsXCqi0dZWDWU0A==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + } + }, + "@aws-sdk/url-parser": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.226.0.tgz", + "integrity": "sha512-p5RLE0QWyP0OcTOLmFcLdVgUcUEzmEfmdrnOxyNzomcYb0p3vUagA5zfa1HVK2azsQJFBv28GfvMnba9bGhObg==", + "optional": true, + "requires": { + "@aws-sdk/querystring-parser": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-base64": { + "version": "3.208.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.208.0.tgz", + "integrity": "sha512-PQniZph5A6N7uuEOQi+1hnMz/FSOK/8kMFyFO+4DgA1dZ5pcKcn5wiFwHkcTb/BsgVqQa3Jx0VHNnvhlS8JyTg==", + "optional": true, + "requires": { + "@aws-sdk/util-buffer-from": "3.208.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-body-length-browser": { + "version": "3.188.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.188.0.tgz", + "integrity": "sha512-8VpnwFWXhnZ/iRSl9mTf+VKOX9wDE8QtN4bj9pBfxwf90H1X7E8T6NkiZD3k+HubYf2J94e7DbeHs7fuCPW5Qg==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-body-length-node": { + "version": "3.208.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.208.0.tgz", + "integrity": "sha512-3zj50e5g7t/MQf53SsuuSf0hEELzMtD8RX8C76f12OSRo2Bca4FLLYHe0TZbxcfQHom8/hOaeZEyTyMogMglqg==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-buffer-from": { + "version": "3.208.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.208.0.tgz", + "integrity": "sha512-7L0XUixNEFcLUGPeBF35enCvB9Xl+K6SQsmbrPk1P3mlV9mguWSDQqbOBwY1Ir0OVbD6H/ZOQU7hI/9RtRI0Zw==", + "optional": true, + "requires": { + "@aws-sdk/is-array-buffer": "3.201.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-config-provider": { + "version": "3.208.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.208.0.tgz", + "integrity": "sha512-DSRqwrERUsT34ug+anlMBIFooBEGwM8GejC7q00Y/9IPrQy50KnG5PW2NiTjuLKNi7pdEOlwTSEocJE15eDZIg==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-defaults-mode-browser": { + "version": "3.234.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.234.0.tgz", + "integrity": "sha512-IHMKXjTbOD8XMz5+2oCOsVP94BYb9YyjXdns0aAXr2NAo7k2+RCzXQ2DebJXppGda1F6opFutoKwyVSN0cmbMw==", + "optional": true, + "requires": { + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/types": "3.226.0", + "bowser": "^2.11.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-defaults-mode-node": { + "version": "3.234.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.234.0.tgz", + "integrity": "sha512-UGjQ+OjBYYhxFVtUY+jtr0ZZgzZh6OHtYwRhFt8IHewJXFCfZTyfsbX20szBj5y1S4HRIUJ7cwBLIytTqMbI5w==", + "optional": true, + "requires": { + "@aws-sdk/config-resolver": "3.234.0", + "@aws-sdk/credential-provider-imds": "3.226.0", + "@aws-sdk/node-config-provider": "3.226.0", + "@aws-sdk/property-provider": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-endpoints": { + "version": "3.245.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.245.0.tgz", + "integrity": "sha512-UNOFquB1tKx+8RT8n82Zb5tIwDyZHVPBg/m0LB0RsLETjr6krien5ASpqWezsXKIR1hftN9uaxN4bvf2dZrWHg==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-hex-encoding": { + "version": "3.201.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.201.0.tgz", + "integrity": "sha512-7t1vR1pVxKx0motd3X9rI3m/xNp78p3sHtP5yo4NP4ARpxyJ0fokBomY8ScaH2D/B+U5o9ARxldJUdMqyBlJcA==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-locate-window": { + "version": "3.208.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.208.0.tgz", + "integrity": "sha512-iua1A2+P7JJEDHVgvXrRJSvsnzG7stYSGQnBVphIUlemwl6nN5D+QrgbjECtrbxRz8asYFHSzhdhECqN+tFiBg==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-middleware": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.226.0.tgz", + "integrity": "sha512-B96CQnwX4gRvQdaQkdUtqvDPkrptV5+va6FVeJOocU/DbSYMAScLxtR3peMS8cnlOT6nL1Eoa42OI9AfZz1VwQ==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-retry": { + "version": "3.229.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.229.0.tgz", + "integrity": "sha512-0zKTqi0P1inD0LzIMuXRIYYQ/8c1lWMg/cfiqUcIAF1TpatlpZuN7umU0ierpBFud7S+zDgg0oemh+Nj8xliJw==", + "optional": true, + "requires": { + "@aws-sdk/service-error-classification": "3.229.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-uri-escape": { + "version": "3.201.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.201.0.tgz", + "integrity": "sha512-TeTWbGx4LU2c5rx0obHeDFeO9HvwYwQtMh1yniBz00pQb6Qt6YVOETVQikRZ+XRQwEyCg/dA375UplIpiy54mA==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-user-agent-browser": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.226.0.tgz", + "integrity": "sha512-PhBIu2h6sPJPcv2I7ELfFizdl5pNiL4LfxrasMCYXQkJvVnoXztHA1x+CQbXIdtZOIlpjC+6BjDcE0uhnpvfcA==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.226.0", + "bowser": "^2.11.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-user-agent-node": { + "version": "3.226.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.226.0.tgz", + "integrity": "sha512-othPc5Dz/pkYkxH+nZPhc1Al0HndQT8zHD4e9h+EZ+8lkd8n+IsnLfTS/mSJWrfiC6UlNRVw55cItstmJyMe/A==", + "optional": true, + "requires": { + "@aws-sdk/node-config-provider": "3.226.0", + "@aws-sdk/types": "3.226.0", + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-utf8-browser": { + "version": "3.188.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.188.0.tgz", + "integrity": "sha512-jt627x0+jE+Ydr9NwkFstg3cUvgWh56qdaqAMDsqgRlKD21md/6G226z/Qxl7lb1VEW2LlmCx43ai/37Qwcj2Q==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + } + }, + "@aws-sdk/util-utf8-node": { + "version": "3.208.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-node/-/util-utf8-node-3.208.0.tgz", + "integrity": "sha512-jKY87Acv0yWBdFxx6bveagy5FYjz+dtV8IPT7ay1E2WPWH1czoIdMAkc8tSInK31T6CRnHWkLZ1qYwCbgRfERQ==", + "optional": true, + "requires": { + "@aws-sdk/util-buffer-from": "3.208.0", + "tslib": "^2.3.1" + } + }, "@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -2832,8 +5002,7 @@ "@types/node": { "version": "18.11.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==", - "dev": true + "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" }, "@types/qs": { "version": "6.9.7", @@ -2867,6 +5036,20 @@ "minipass": "^3.3.5" } }, + "@types/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + }, + "@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==", + "requires": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, "@types/yargs": { "version": "17.0.19", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", @@ -3027,6 +5210,29 @@ } } }, + "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 + }, + "bson": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.1.tgz", + "integrity": "sha512-XkuFtlCzi0WSy8D6PMhvrQ/q8VlZHN/2bJ/shJglwuA6TPD2ZP/hHLB7iDxOEWVINHN/UVTxP4pqZqOKMXPIXg==", + "requires": { + "buffer": "^5.6.0" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -3378,6 +5584,15 @@ "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==" }, + "fast-xml-parser": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.0.11.tgz", + "integrity": "sha512-4aUg3aNRR/WjQAcpceODG1C3x3lFANXRo8+1biqfieHmg9pyMt7qB4lQV/Ta6sJCTbA5vfD8fnA8S54JATiFUA==", + "optional": true, + "requires": { + "strnum": "^1.0.5" + } + }, "finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -3633,11 +5848,21 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -3784,6 +6009,12 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" }, + "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", @@ -3844,6 +6075,27 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" }, + "mongodb": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.13.0.tgz", + "integrity": "sha512-+taZ/bV8d1pYuHL4U+gSwkhmDrwkWbH1l4aah4YpmpscMwgFBkufIKxgP/G7m87/NUuQzc2Z75ZTI7ZOyqZLbw==", + "requires": { + "@aws-sdk/credential-providers": "^3.186.0", + "bson": "^4.7.0", + "mongodb-connection-string-url": "^2.5.4", + "saslprep": "^1.0.3", + "socks": "^2.7.1" + } + }, + "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==", + "requires": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4074,6 +6326,15 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "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" + } + }, "saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", @@ -4150,12 +6411,35 @@ "object-inspect": "^1.9.0" } }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "optional": true }, + "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, + "requires": { + "memory-pager": "^1.0.2" + } + }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -4187,6 +6471,12 @@ "ansi-regex": "^5.0.1" } }, + "strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "optional": true + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -4260,6 +6550,12 @@ "yn": "3.1.1" } }, + "tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "optional": true + }, "tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", diff --git a/package.json b/package.json index 33338c9..d76cf81 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "cron": "^2.1.0", "express": "^4.18.2", "lzma-native": "^8.0.6", + "mongodb": "^4.13.0", "openpgp": "^5.5.0", "tar": "^6.1.13", "yaml": "^2.2.1", diff --git a/src/express_route.ts b/src/express_route.ts index 0e432a2..5ae3919 100644 --- a/src/express_route.ts +++ b/src/express_route.ts @@ -12,8 +12,8 @@ import path from "node:path"; export default async function main(configPath: string) { // Load config - const packInfos = new distManegerPackages() let repositoryConfig = await getConfig(configPath); + const packInfos = new distManegerPackages(repositoryConfig); // Express app const app = express(); @@ -34,12 +34,12 @@ export default async function main(configPath: string) { }); // Sources list - app.get(["/source_list", "/sources.list"], (req, res) => { + app.get(["/source_list", "/sources.list"], async (req, res) => { const remotePath = path.posix.resolve(req.baseUrl + req.path, ".."), protocol = req.headers["x-forwarded-proto"] ?? req.protocol, hostname = process.env["RAILWAY_STATIC_URL"] ?? `${req.hostname}:${req.socket.localPort}`, host = repositoryConfig["apt-config"]?.sourcesHost ?? `${protocol}://${hostname}${remotePath}`, - concatPackage = packInfos.getAllDistribuitions(), + concatPackage = await packInfos.getAllDistribuitions(), type = req.query.type ?? req.query.t, Conflicting = !!(req.query.conflicting ?? req.query.c); if (type === "json") { @@ -54,12 +54,12 @@ export default async function main(configPath: string) { }); // Download - app.get(["/pool", "/"], (_req, res) => res.json(packInfos.getAllDistribuitions())); - app.get("/pool/:dist", (req, res) => res.json(packInfos.getDistribuition(req.params.dist))); - app.get("/pool/:dist/:suite", ({params: {dist, suite}}, res) => res.json(packInfos.getPackageInfo({dist, suite}))); - app.get("/pool/:dist/:suite/:arch", ({params: {dist, suite, arch}}, res) => res.json(packInfos.getPackageInfo({dist, suite, arch}))); - app.get("/pool/:dist/:suite/:arch/:packageName", ({params: {dist, suite, arch, packageName}}, res) => res.json(packInfos.getPackageInfo({dist, suite, arch, packageName}))); - app.get("/pool/:dist/:suite/:arch/:packageName/:version", ({params: {dist, suite, arch, packageName, version}}, res) => res.json(packInfos.getPackageInfo({dist, suite, arch, packageName, version}))); + app.get(["/pool", "/"], async (_req, res) => res.json(await packInfos.getAllDistribuitions())); + app.get("/pool/:dist", async (req, res) => res.json(await packInfos.getDistribuition(req.params.dist))); + app.get("/pool/:dist/:suite", async ({params: {dist, suite}}, res) => res.json(await packInfos.getPackageInfo({dist, suite}))); + app.get("/pool/:dist/:suite/:arch", async ({params: {dist, suite, arch}}, res) => res.json(await packInfos.getPackageInfo({dist, suite, arch}))); + app.get("/pool/:dist/:suite/:arch/:packageName", async ({params: {dist, suite, arch, packageName}}, res) => res.json(await packInfos.getPackageInfo({dist, suite, arch, packageName}))); + app.get("/pool/:dist/:suite/:arch/:packageName/:version", async ({params: {dist, suite, arch, packageName, version}}, res) => res.json(await packInfos.getPackageInfo({dist, suite, arch, packageName, version}))); app.get("/pool/:dist/:suite/:arch/:packageName/:version/download.deb", async ({params: {dist, suite, arch, packageName, version}}, res, next) => packInfos.getPackageStream(dist, suite, arch, packageName, version).then(data => data.stream.pipe(res.writeHead(200, {"Content-Type": "application/x-debian-package", "Content-Length": data.control.Size, "Content-Disposition": `attachment; filename="${packageName}_${version}_${arch}.deb"`, "SHA256_hash": data.control.SHA256, "MD5Sum_hash": data.control.MD5sum}))).catch(next)); app.get("/dists/(./)?:dist/:suite/binary-:arch/Packages(.(xz|gz)|)", (req, res) => { @@ -99,7 +99,7 @@ export default async function main(configPath: string) { // Release async function createReleaseV1(dist: string) { - const { suites, archs } = packInfos.getDistribuition(dist); + const { suites, archs } = await packInfos.getDistribuition(dist); const distConfig = repositoryConfig.repositories[dist]; if (!distConfig) throw new Error("Dist not found"); const ReleaseLines = []; diff --git a/src/mirror.ts b/src/mirror.ts index 6cf342c..f8dcb5e 100644 --- a/src/mirror.ts +++ b/src/mirror.ts @@ -82,7 +82,6 @@ export async function getPackages(uri: string, options: {dist: string, suite?: s const hashs: {file: string, Package: DebianPackage.debianControl}[] = []; async function addPackages(dist: string, file: string, fn?: (data: DebianPackage.debianControl) => void) { const urlRequest = `${uri}/dists/${dist}/${file}`; - console.log(`Requesting ${urlRequest}`); await new Promise(async (done, reject) => { const stream = (urlRequest.endsWith(".gz")||urlRequest.endsWith(".xz")) ? (await httpRequest.pipeFetch(urlRequest)).pipe(urlRequest.endsWith(".gz") ? zlib.createGunzip() : lzmaDecompressor()) : await httpRequest.pipeFetch(urlRequest); stream.on("error", (err: any) => { diff --git a/src/repoConfig.ts b/src/repoConfig.ts index de75987..85893a0 100644 --- a/src/repoConfig.ts +++ b/src/repoConfig.ts @@ -1,12 +1,15 @@ import coreUtils, { DebianPackage, DockerRegistry, extendFs, extendsCrypto, httpRequest } from "@sirherobrine23/coreutils"; +import { createReadStream, createWriteStream } from "node:fs"; +import { MongoClient, ServerApiVersion } from "mongodb"; import { Compressor as lzmaCompressor } from "lzma-native"; import { Readable, Writable } from "node:stream"; import { debianControl } from "@sirherobrine23/coreutils/src/deb.js"; import { createGzip } from "node:zlib"; +import { format } from "node:util"; import yaml from "yaml"; import path from "node:path"; import fs from "node:fs/promises"; -import { format } from "node:util"; +import tar from "tar"; export type apt_config = { origin?: string, @@ -81,6 +84,11 @@ export type backendConfig = Partial<{ private: string, public: string, passphrase?: string + }, + mongodb?: { + uri: string, + db?: string, + collection?: string, } }, repositories: { @@ -155,6 +163,14 @@ export async function getConfig(config: string) { passphrase }; } + if (rootData.mongodb) { + if (!rootData.mongodb.uri) throw new Error("mongodb.uri not defined"); + fixedConfig["apt-config"].mongodb = { + uri: rootData.mongodb.uri, + db: rootData.mongodb.db ?? "apt-stream", + collection: rootData.mongodb.collection ?? "packages" + }; + } } if (fixedConfig["apt-config"].pgpKey) { const pgpKey = fixedConfig["apt-config"].pgpKey; @@ -288,17 +304,119 @@ type distObject = { } } +type dbDist = { + control: debianControl, + repositoryConfig?: repository, + dist: string, + suite: string, + getfile: repository & {file: string, blobLayer?: string} +}; + export class distManegerPackages { public distribuitions: distObject = {}; - public addDistribuition(distribuition: string) { + public mongoClinte?: MongoClient; + public internalDist: distObject = {}; + public config: backendConfig; + constructor(config: backendConfig) { + this.config = config; + if (config["apt-config"]?.mongodb) { + this.mongoClinte = new MongoClient(config["apt-config"]?.mongodb?.uri, { + serverApi: ServerApiVersion.v1, + }); + this.mongoClinte.connect(); + } + } + + async getPackages(dist?: string, suite?: string): Promise { + let repo: distObject = {}; + if (!this.mongoClinte) repo = this.distribuitions; + else { + if (dist && typeof dist !== "string") throw new Error("dist must be a string"); + if (suite && typeof suite !== "string") throw new Error("suite must be a string"); + const saveFile = this.config["apt-config"]?.saveFiles; + const rootPool = this.config["apt-config"]?.poolPath; + const collection = this.mongoClinte.db(this.config["apt-config"]?.mongodb?.db ?? "packages").collection(this.config["apt-config"]?.mongodb.collection ?? "packages"); + for (const dataDB of await collection.find({dist, suite}).toArray()) { + const repository = dataDB.getfile, control = dataDB.control; + if (dist && dist !== dataDB.dist) continue; + if (suite && suite !== dataDB.suite) continue; + async function getStream() { + if (repository.from === "mirror") { + const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); + if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); + return coreUtils.httpRequest.pipeFetch(dataDB.getfile.file); + } else if (repository.from === "oci") { + const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); + if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); + const registry = await coreUtils.DockerRegistry(repository.image, repository.platfom_target); + return new Promise((done, reject) => registry.blobLayerStream(dataDB.getfile.blobLayer).then(stream => { + stream.on("error", reject); + stream.pipe(tar.list({ + async onentry(getEntry) { + if (getEntry.path !== dataDB.getfile.file) return null; + if (saveFile) { + const mainPath = path.resolve(filePool, ".."); + if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); + getEntry.pipe(createWriteStream(filePool)); + } + return done(getEntry as any); + } + // @ts-ignore + }).on("error", reject)); + }).catch(reject)); + } else if (repository.from === "github_release" || repository.from === "github_tree") { + const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); + if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); + return coreUtils.httpRequest.pipeFetch({ + url: dataDB.getfile.file, + headers: (repository.token ? {"Authorization": `token ${repository.token}`} : {}) + }) + } else if (repository.from === "google_drive") { + const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); + if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); + const client_id = repository.appSettings.client_id; + const client_secret = repository.appSettings.client_secret; + const token = repository.appSettings.token; + const googleDriver = await coreUtils.googleDriver.GoogleDriver(client_id, client_secret, { + token, + async authCallback(url, token) { + if (url) console.log("Please visit this url to auth google driver: %s", url); + else console.log("Google driver auth success, please save token to config file, token: %s", token); + }, + }); + return googleDriver.getFileStream(dataDB.getfile.file); + } else if (repository.from === "oracle_bucket") { + const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); + if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); + const oracleBucket = await coreUtils.oracleBucket(repository.region as any, repository.bucketName, repository.bucketNamespace, repository.auth); + return oracleBucket.getFileStream(dataDB.getfile.file); + } + + return null; + } + if (!repo[dataDB.dist]) repo[dataDB.dist] = {}; + if (!repo[dataDB.dist][dataDB.suite]) repo[dataDB.dist][dataDB.suite] = {}; + if (!repo[dataDB.dist][dataDB.suite][control.Architecture]) repo[dataDB.dist][dataDB.suite][control.Architecture] = []; + repo[dataDB.dist][dataDB.suite][control.Architecture].push({ + getStream, + repositoryConfig: dataDB.repositoryConfig, + control, + }); + console.log("add package %s %s %s %s", dataDB.dist, dataDB.suite, control.Architecture, control.Package); + }; + } + return repo; + } + + public async addDistribuition(distribuition: string) { if (!this.distribuitions[distribuition]) this.distribuitions[distribuition] = {}; return this.distribuitions[distribuition]; } - public addSuite(distribuition: string, suite: string) { + public async addSuite(distribuition: string, suite: string) { if (!this.distribuitions[distribuition][suite]) this.distribuitions[distribuition][suite] = {}; return this.distribuitions[distribuition][suite]; } - public addArch(distribuition: string, suite: string, arch: string) { + public async addArch(distribuition: string, suite: string, arch: string) { if (!this.distribuitions[distribuition][suite][arch]) this.distribuitions[distribuition][suite][arch] = []; return this.distribuitions[distribuition][suite][arch]; } @@ -313,20 +431,39 @@ export class distManegerPackages { * @param getStream * @returns */ - public addPackage(distribuition: string, suite: string, packageData: packageData) { + public async addPackage(distribuition: string, suite: string, packageData: packageData) { + const dist = await this.getPackages(distribuition, suite); this.addDistribuition(distribuition); this.addSuite(distribuition, suite); this.addArch(distribuition, suite, packageData.control.Architecture); - const currentPackages = this.distribuitions[distribuition][suite][packageData.control.Architecture]; - if (currentPackages.some(pkg => pkg.control.Package === packageData.control.Package)) { - if (currentPackages.some(pkg => pkg.control.Version === packageData.control.Version && pkg.control.Package === packageData.control.Package)) { - const index = currentPackages.findIndex(pkg => pkg.control.Version === packageData.control.Version && pkg.control.Package === packageData.control.Package); - console.info("[INFO]: Replace %s, with version %s, target arch %s, index number %f", packageData.control.Package, packageData.control.Version, packageData.control.Architecture, index); - return this.distribuitions[distribuition][suite][packageData.control.Architecture][index] = packageData; + const currentPackages = dist[distribuition]?.[suite]?.[packageData.control.Architecture] ?? []; + if (!this.mongoClinte) { + if (currentPackages.some(pkg => pkg.control.Package === packageData.control.Package)) { + if (currentPackages.some(pkg => pkg.control.Version === packageData.control.Version && pkg.control.Package === packageData.control.Package)) { + const index = currentPackages.findIndex(pkg => pkg.control.Version === packageData.control.Version && pkg.control.Package === packageData.control.Package); + return dist[distribuition][suite][packageData.control.Architecture][index] = packageData; + } } + dist[distribuition][suite][packageData.control.Architecture].push(packageData); + } else { + const collection = this.mongoClinte.db(this.config["apt-config"]?.mongodb?.db ?? "packages").collection(this.config["apt-config"]?.mongodb.collection ?? "packages"); + const currentPackages = await collection.findOne({ + dist: distribuition, + suite, + cotrol: { + Package: packageData.control.Package, + Version: packageData.control.Version, + Architecture: packageData.control.Architecture, + } + }); + if (currentPackages) await collection.deleteOne(currentPackages); + await collection.insertOne({ + dist: distribuition, + suite, + control: packageData.control, + repository: packageData.repositoryConfig + }); } - console.info("[INFO]: Add %s, with version %s, target arch %s", packageData.control.Package, packageData.control.Version, packageData.control.Architecture); - this.distribuitions[distribuition][suite][packageData.control.Architecture].push(packageData); return packageData; } @@ -341,9 +478,9 @@ export class distManegerPackages { return data; } - public getDistribuition(distName: string) { - const dist = this.distribuitions[distName]; - if (!dist) throw new Error("Distribuition not exists"); + public async getDistribuition(distName: string) { + const dist = (await this.getPackages(distName))[distName]; + if (!dist) return null; const suites = Object.keys(dist); const suiteData = suites.map(suite => { const Packages = Object.keys(dist[suite]).map(arch => dist[suite][arch].map(packageInfo => packageInfo.control)).flat(); @@ -362,21 +499,23 @@ export class distManegerPackages { }; } - public getAllDistribuitions() { - return Object.keys(this.distribuitions).map(dist => this.getDistribuition(dist)).flat(); + public async getAllDistribuitions() { + const dist = await this.getPackages(); + return (await Promise.all(Object.keys(dist).map(dist => this.getDistribuition(dist)))).flat().filter(Boolean); } - public getPackageInfo(info: {dist: string, suite?: string, arch?: string, packageName?: string, version?: string}) { + public async getPackageInfo(info: {dist: string, suite?: string, arch?: string, packageName?: string, version?: string}) { const packageDateObject: {[k: string]: {[l: string]: {[a: string]: DebianPackage.debianControl[]}}} = {}; - for (const dist in this.distribuitions) { + const distData = await this.getPackages(info.dist, info.suite); + for (const dist in distData) { if (info.dist && info.dist !== dist) continue; packageDateObject[dist] = {}; - for (const suite in this.distribuitions[dist]) { + for (const suite in distData[dist]) { if (info.suite && info.suite !== suite) continue; packageDateObject[dist][suite] = {}; - for (const arch in this.distribuitions[dist][suite]) { + for (const arch in distData[dist][suite]) { if (info.arch && info.arch !== arch) continue; - packageDateObject[dist][suite][arch] = this.distribuitions[dist][suite][arch].map(pkg => pkg.control).filter(pkg => (!info.packageName || pkg.Package === info.packageName) && (!info.version || pkg.Version === info.version)); + packageDateObject[dist][suite][arch] = distData[dist][suite][arch].map(pkg => pkg.control).filter(pkg => (!info.packageName || pkg.Package === info.packageName) && (!info.version || pkg.Version === info.version)); } } } @@ -397,16 +536,17 @@ export class distManegerPackages { } public async getPackageStream(distribuition: string, suite: string, arch: string, packageName: string, version: string) { - if (!this.distribuitions[distribuition]) throw new Error("Distribuition not exists"); - if (!this.distribuitions[distribuition][suite]) throw new Error("Suite not exists"); - if (!this.distribuitions[distribuition][suite][arch]) throw new Error("Arch not exists"); - const packageData = this.distribuitions[distribuition][suite][arch].find(pkg => pkg.control.Package === packageName && pkg.control.Version === version); + const dist = (await this.getPackages(distribuition))[distribuition]; + if (!dist) throw new Error("Distribuition not exists"); + if (!dist[suite]) throw new Error("Suite not exists"); + if (!dist[suite][arch]) throw new Error("Arch not exists"); + const packageData = dist[suite][arch].find(pkg => pkg.control.Package === packageName && pkg.control.Version === version); if (!packageData) throw new Error("Package not exists"); return Promise.resolve(packageData.getStream()).then(stream => ({control: packageData.control, repository: packageData.repositoryConfig, stream})); } public async createPackages(options?: {compress?: "gzip" | "xz", writeStream?: Writable, singlePackages?: boolean, dist?: string, package?: string, arch?: string, suite?: string}) { - const distribuition = this.distribuitions; + const distribuition = await this.getPackages(options?.dist); const rawWrite = new Readable({read(){}}); let size = 0, addbreak = false, hash: ReturnType|undefined; if (options?.compress === "gzip") { -- 2.45.2 From 629bf020913d89377d8eac3faddf5dc2f31a4edb Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Mon, 9 Jan 2023 21:19:50 -0300 Subject: [PATCH 2/6] update data --- .vscode/launch.json | 5 +- package-lock.json | 63 ----- package.json | 2 - src/express_route.ts | 570 ++++++++++++------------------------------- src/index.ts | 50 +++- src/packagesData.ts | 382 +++++++++++++++++++++++++++++ src/repoConfig.ts | 325 +----------------------- 7 files changed, 602 insertions(+), 795 deletions(-) create mode 100644 src/packagesData.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index ccd8616..e63506e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,7 +12,10 @@ "skipFiles": ["/**", "node_modules/**"], "cwd": "${workspaceRoot}", "runtimeExecutable": "ts-node", - "args": ["src/index.ts", "server"] + "args": ["src/index.ts", "server"], + "env": { + "DISABLE_CLUSTER": "true" + } } ] } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 09f6122..f6d45fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "license": "GPL-2.0", "dependencies": { "@sirherobrine23/coreutils": "^2.2.5", - "cron": "^2.1.0", "express": "^4.18.2", "lzma-native": "^8.0.6", "mongodb": "^4.13.0", @@ -23,7 +22,6 @@ "apt-stream": "src/index.js" }, "devDependencies": { - "@types/cron": "^2.0.0", "@types/express": "^4.17.15", "@types/lzma-native": "^4.0.1", "@types/node": "^18.11.18", @@ -1356,16 +1354,6 @@ "@types/node": "*" } }, - "node_modules/@types/cron": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/cron/-/cron-2.0.0.tgz", - "integrity": "sha512-xZM08fqvwIXgghtPVkSPKNgC+JoMQ2OHazEvyTKnNf7aWu1aB6/4lBbQFrb03Td2cUGG7ITzMv3mFYnMu6xRaQ==", - "dev": true, - "dependencies": { - "@types/luxon": "*", - "@types/node": "*" - } - }, "node_modules/@types/express": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz", @@ -1394,12 +1382,6 @@ "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" }, - "node_modules/@types/luxon": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.2.0.tgz", - "integrity": "sha512-lGmaGFoaXHuOLXFvuju2bfvZRqxAqkHPx9Y9IQdQABrinJJshJwfNCKV+u7rR3kJbiqfTF/NhOkcxxAFrObyaA==", - "dev": true - }, "node_modules/@types/lzma-native": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/lzma-native/-/lzma-native-4.0.1.tgz", @@ -1851,14 +1833,6 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, - "node_modules/cron": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cron/-/cron-2.1.0.tgz", - "integrity": "sha512-Hq7u3P8y7UWYvsZbSKHHJDVG0VO9O7tp2qljxzTScelcTODBfCme8AIhnZsFwmQ9NchZ3hr2uNr+s3DSms7q6w==", - "dependencies": { - "luxon": "^1.23.x" - } - }, "node_modules/cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -2721,14 +2695,6 @@ "node": ">=10" } }, - "node_modules/luxon": { - "version": "1.28.1", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.1.tgz", - "integrity": "sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==", - "engines": { - "node": "*" - } - }, "node_modules/lzma-native": { "version": "8.0.6", "resolved": "https://registry.npmjs.org/lzma-native/-/lzma-native-8.0.6.tgz", @@ -4940,16 +4906,6 @@ "@types/node": "*" } }, - "@types/cron": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/cron/-/cron-2.0.0.tgz", - "integrity": "sha512-xZM08fqvwIXgghtPVkSPKNgC+JoMQ2OHazEvyTKnNf7aWu1aB6/4lBbQFrb03Td2cUGG7ITzMv3mFYnMu6xRaQ==", - "dev": true, - "requires": { - "@types/luxon": "*", - "@types/node": "*" - } - }, "@types/express": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz", @@ -4978,12 +4934,6 @@ "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" }, - "@types/luxon": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.2.0.tgz", - "integrity": "sha512-lGmaGFoaXHuOLXFvuju2bfvZRqxAqkHPx9Y9IQdQABrinJJshJwfNCKV+u7rR3kJbiqfTF/NhOkcxxAFrObyaA==", - "dev": true - }, "@types/lzma-native": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/lzma-native/-/lzma-native-4.0.1.tgz", @@ -5336,14 +5286,6 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, - "cron": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cron/-/cron-2.1.0.tgz", - "integrity": "sha512-Hq7u3P8y7UWYvsZbSKHHJDVG0VO9O7tp2qljxzTScelcTODBfCme8AIhnZsFwmQ9NchZ3hr2uNr+s3DSms7q6w==", - "requires": { - "luxon": "^1.23.x" - } - }, "cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -5983,11 +5925,6 @@ "yallist": "^4.0.0" } }, - "luxon": { - "version": "1.28.1", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.1.tgz", - "integrity": "sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==" - }, "lzma-native": { "version": "8.0.6", "resolved": "https://registry.npmjs.org/lzma-native/-/lzma-native-8.0.6.tgz", diff --git a/package.json b/package.json index d76cf81..e0e1ab0 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ "build": "tsc" }, "devDependencies": { - "@types/cron": "^2.0.0", "@types/express": "^4.17.15", "@types/lzma-native": "^4.0.1", "@types/node": "^18.11.18", @@ -45,7 +44,6 @@ }, "dependencies": { "@sirherobrine23/coreutils": "^2.2.5", - "cron": "^2.1.0", "express": "^4.18.2", "lzma-native": "^8.0.6", "mongodb": "^4.13.0", diff --git a/src/express_route.ts b/src/express_route.ts index 5ae3919..5a89bda 100644 --- a/src/express_route.ts +++ b/src/express_route.ts @@ -1,211 +1,174 @@ -import coreUtils, { DebianPackage, httpRequestGithub, httpRequest, DockerRegistry, extendFs } from "@sirherobrine23/coreutils"; -import { getConfig, distManegerPackages } from "./repoConfig.js"; -import { createReadStream, createWriteStream, watchFile, promises as fs } from "node:fs"; -import { getPackages } from "./mirror.js"; +import { Compressor as lzmaCompress } from "lzma-native"; +import { createGzip } from "node:zlib"; +import { getConfig } from "./repoConfig.js"; import { Readable } from "node:stream"; -import { CronJob } from "cron"; -import { format } from "node:util"; +import package_maneger from "./packagesData.js"; +import coreUtils from "@sirherobrine23/coreutils"; +import cluster from "node:cluster"; import express from "express"; import openpgp from "openpgp"; -import tar from "tar"; -import path from "node:path"; -export default async function main(configPath: string) { - // Load config - let repositoryConfig = await getConfig(configPath); - const packInfos = new distManegerPackages(repositoryConfig); - - // Express app +export default async function initApp(config: string) { + const packageConfig = await getConfig(config); + const packageManeger = await package_maneger(packageConfig); const app = express(); - app.disable("x-powered-by").disable("etag").use(express.json()).use(express.urlencoded({ extended: true })).use((req, res, next) => { - res.json = (data) => res.setHeader("Content-Type", "application/json").send(JSON.stringify(data, null, 2)); - const requestInitial = Date.now(); - console.log("[%s]: Method: %s, From: %s, Path %s", requestInitial, req.method, req.ip, req.path); - res.once("close", () => console.log("[%s]: Method: %s, From: %s, Path %s, Status: %s, Time: %sms", Date.now(), req.method, req.ip, req.path, res.statusCode, Date.now() - requestInitial)); + app.disable("x-powered-by").disable("etag").use(express.json()).use(express.urlencoded({extended: true})).use((req, res, next) => { + res.json = data => res.setHeader("Content-Type", "application/json").send(JSON.stringify(data, null, 2)); + const cluserID = cluster.worker?.id ?? 0; + // [%s TIME STAMP, cluserID: %f]: Path: %s, Method: %s, IP: %s + console.log("[%s, cluserID: %f]: Path: %s, Method: %s, IP: %s", new Date().toISOString(), cluserID, req.path, req.method, req.ip); + res.on("close", () => console.log("[%s, cluserID: %f]: Path: %s, Method: %s, IP: %s, Status: %f", new Date().toISOString(), cluserID, req.path, req.method, req.ip, res.statusCode)); next(); }); - - // Public key - app.get(["/public_key", "/public.gpg"], async ({res}) => { - const Key = repositoryConfig["apt-config"]?.pgpKey; - if (!Key) return res.status(400).json({error: "This repository no sign Packages files"}); - const pubKey = (await openpgp.readKey({ armoredKey: Key.public })).armor(); - return res.setHeader("Content-Type", "application/pgp-keys").send(pubKey); - }); - - // Sources list - app.get(["/source_list", "/sources.list"], async (req, res) => { - const remotePath = path.posix.resolve(req.baseUrl + req.path, ".."), - protocol = req.headers["x-forwarded-proto"] ?? req.protocol, - hostname = process.env["RAILWAY_STATIC_URL"] ?? `${req.hostname}:${req.socket.localPort}`, - host = repositoryConfig["apt-config"]?.sourcesHost ?? `${protocol}://${hostname}${remotePath}`, - concatPackage = await packInfos.getAllDistribuitions(), - type = req.query.type ?? req.query.t, - Conflicting = !!(req.query.conflicting ?? req.query.c); - if (type === "json") { - return res.json({ - host, - distribuitions: concatPackage - }); - } else if (type === "deb822") {} - let sourcesList = ""; - concatPackage.forEach((dist) => sourcesList += format("deb %s %s %s\n", host, (Conflicting ? "./" : "")+dist.dist, dist.suites.join(" "))); - return res.status(200).setHeader("Content-Type", "text/plain").send(sourcesList); - }); - - // Download - app.get(["/pool", "/"], async (_req, res) => res.json(await packInfos.getAllDistribuitions())); - app.get("/pool/:dist", async (req, res) => res.json(await packInfos.getDistribuition(req.params.dist))); - app.get("/pool/:dist/:suite", async ({params: {dist, suite}}, res) => res.json(await packInfos.getPackageInfo({dist, suite}))); - app.get("/pool/:dist/:suite/:arch", async ({params: {dist, suite, arch}}, res) => res.json(await packInfos.getPackageInfo({dist, suite, arch}))); - app.get("/pool/:dist/:suite/:arch/:packageName", async ({params: {dist, suite, arch, packageName}}, res) => res.json(await packInfos.getPackageInfo({dist, suite, arch, packageName}))); - app.get("/pool/:dist/:suite/:arch/:packageName/:version", async ({params: {dist, suite, arch, packageName, version}}, res) => res.json(await packInfos.getPackageInfo({dist, suite, arch, packageName, version}))); - app.get("/pool/:dist/:suite/:arch/:packageName/:version/download.deb", async ({params: {dist, suite, arch, packageName, version}}, res, next) => packInfos.getPackageStream(dist, suite, arch, packageName, version).then(data => data.stream.pipe(res.writeHead(200, {"Content-Type": "application/x-debian-package", "Content-Length": data.control.Size, "Content-Disposition": `attachment; filename="${packageName}_${version}_${arch}.deb"`, "SHA256_hash": data.control.SHA256, "MD5Sum_hash": data.control.MD5sum}))).catch(next)); - - app.get("/dists/(./)?:dist/:suite/binary-:arch/Packages(.(xz|gz)|)", (req, res) => { - if (req.path.endsWith(".gz")) { - packInfos.createPackages({ - compress: "gzip", - dist: req.params.dist, - arch: req.params.arch, - suite: req.params.suite, - writeStream: res.writeHead(200, { - "Content-Encoding": "gzip", - "Content-Type": "application/x-gzip" - }), - }); - } else if (req.path.endsWith(".xz")) { - packInfos.createPackages({ - compress: "xz", - dist: req.params.dist, - arch: req.params.arch, - suite: req.params.suite, - writeStream: res.writeHead(200, { - "Content-Encoding": "xz", - "Content-Type": "application/x-xz" - }), - }); - } else { - packInfos.createPackages({ - dist: req.params.dist, - arch: req.params.arch, - suite: req.params.suite, - writeStream: res.writeHead(200, { - "Content-Type": "text/plain" - }), - }); + app.get("/pool/:dist/:suite/:package/:arch/:version/download.deb", async ({params: {dist, suite, package: packageName, arch, version}}, {writeHead}, next) => { + try { + const data = (await packageManeger.getPackages(dist, suite, packageName, arch, version))?.at(-1); + if (!data) return next(new Error("Not Found")); + const fileStream = await data.getFileStream(); + fileStream.pipe(writeHead(200, { + "Content-Type": "application/x-debian-package", + "Content-Length": data.control.Size, + "Content-Disposition": `attachment; filename="${packageName}_${version}_${arch}.deb"`, + "SHA256_hash": data.control.SHA256, + "MD5Sum_hash": data.control.MD5sum + })); + } catch (err) { + next(err); } }); + app.get("/pool/:dist/:suite/:package/:arch/:version", (req, res, next) => packageManeger.getPackages(req.params.dist, req.params.suite, req.params.package, req.params.arch, req.params.version).then(data => res.json(data.at(-1).control)).catch(next)); + app.get("/pool/:dist/:suite/:package/:arch", (req, res, next) => packageManeger.getPackages(req.params.dist, req.params.suite, req.params.package, req.params.arch).then(data => res.json(data.map(({control}) => control))).catch(next)); + app.get("/pool/:dist/:suite/:package", (req, res, next) => packageManeger.getPackages(req.params.dist, req.params.suite, req.params.package).then(data => res.json(data.map(({control}) => control))).catch(next)); + app.get("/pool/:dist/:suite", (req, res, next) => packageManeger.getPackages(req.params.dist, req.params.suite).then(data => res.json(data.map(x => x.control))).catch(next)); + app.get("/pool/:dist", (req, res, next) => packageManeger.getPackages(req.params.dist).then(data => res.json(data.reduce((old, current) => { + if (!old[current.suite]) old[current.suite] = []; + old[current.suite].push(current.control); + return old; + }, {}))).catch(next)); + + app.get(["/", "/pool"], ({}, res, next) => packageManeger.getPackages().then(data => res.json(data.reduce((old, current) => { + if (!old[current.dist]) old[current.dist] = {}; + if (!old[current.dist][current.suite]) old[current.dist][current.suite] = []; + old[current.dist][current.suite].push(current.control); + return old; + }, {}))).catch(next)); + + // Create Package, Package.gz and Package.xz + async function createPackages(dist: string, suite: string, arch: string) { + let rawSize = 0, gzipSize = 0, lzmaSize = 0; + const mainReadstream = new Readable({read(){}}), rawSUMs = coreUtils.extendsCrypto.createHashAsync("all", mainReadstream).then(hash => ({size: rawSize, hash})); + const gzip = mainReadstream.pipe(createGzip()), gzipSUMs = coreUtils.extendsCrypto.createHashAsync("all", gzip).then(hash => ({size: gzipSize, hash})); + const lzma = mainReadstream.pipe(lzmaCompress()), lzmaSUMs = coreUtils.extendsCrypto.createHashAsync("all", lzma).then(hash => ({size: lzmaSize, hash})); + mainReadstream.on("data", data => rawSize += data.length); + gzip.on("data", data => gzipSize += data.length); + lzma.on("data", data => lzmaSize += data.length); + + const packages = await packageManeger.getPackages(dist, suite, undefined, arch); + if (!packages.length) throw new Error("Check is dist or suite have packages"); + let fist = true; + for (const {control} of packages) { + if (!(control.Size && (control.MD5sum || control.SHA256 || control.SHA1))) continue; + if (fist) fist = false; else mainReadstream.push("\n\n"); + control.Filename = `pool/${dist}/${suite}/${control.Package}/${control.Architecture}/${control.Version}/download.deb`; + mainReadstream.push(Object.keys(control).map(key => mainReadstream.push(`${key}: ${control[key]}`)).join("\n")); + } + mainReadstream.push(null); + + return { + raw: mainReadstream, + gzip, + lzma, + SUMs: { + raw: rawSUMs, + gzip: gzipSUMs, + lzma: lzmaSUMs + } + }; + } + app.get("/dists/(./)?:dist/:suite/binary-:arch/Packages(.(xz|gz)|)", async ({params: {dist, suite, arch}, path: reqPath}, res, next) => createPackages(dist, suite, arch).then(packages => { + if (reqPath.endsWith(".gz")) return packages.gzip.pipe(res); + else if (reqPath.endsWith(".xz")) return packages.lzma.pipe(res); + else return packages.raw.pipe(res); + }).catch(next)); // Release - async function createReleaseV1(dist: string) { - const { suites, archs } = await packInfos.getDistribuition(dist); - const distConfig = repositoryConfig.repositories[dist]; - if (!distConfig) throw new Error("Dist not found"); - const ReleaseLines = []; - - // Origin - const Origin = distConfig["apt-config"]?.origin ?? repositoryConfig["apt-config"]?.origin; - if (Origin) ReleaseLines.push(`Origin: ${Origin}`); - - // Lebel - const Label = distConfig["apt-config"]?.label ?? repositoryConfig["apt-config"]?.label; - if (Label) ReleaseLines.push(`Label: ${Label}`); - - // Codename if exists - const codename = distConfig["apt-config"]?.codename ?? repositoryConfig["apt-config"]?.codename; - if (codename) ReleaseLines.push(`Codename: ${codename}`); + async function createRelease(dist: string) { + const packagesArray = await packageManeger.getPackages(dist); + if (!packagesArray.length) throw new Error("Check is dist have packages"); + const Release: {[key: string]: string|string[]} = {}; // Date - ReleaseLines.push(`Date: ${new Date().toUTCString()}`); + Release.Date = new Date().toUTCString(); - // Architectures - if (archs.length === 0) throw new Error("No architectures found"); - ReleaseLines.push(`Architectures: ${archs.join(" ")}`); + // Origin + const Origin = packageConfig["apt-config"]?.origin ?? packagesArray.find(x => x.aptConfig?.origin)?.aptConfig?.origin; + if (Origin) Release.Origin = Origin; + + // Lebel + const Label = packageConfig["apt-config"]?.label ?? packagesArray.find(x => x.aptConfig?.label)?.aptConfig?.label; + if (Label) Release.Label = Label; + + // Codename + const Codename = packageConfig["apt-config"]?.codename ?? packagesArray.find(x => x.aptConfig?.codename)?.aptConfig?.codename; + if (Codename) Release.Codename = Codename; + + // Archs + const Archs = ([...(new Set(packagesArray.map(x => x.control.Architecture)))]); + if (!Archs.length) throw new Error("Check is dist have packages"); + Release.Architectures = Archs.join(" "); // Components - if (suites.length === 0) throw new Error("No suites found"); - ReleaseLines.push(`Components: ${suites.join(" ")}`); + const Components = ([...(new Set(packagesArray.map(x => x.suite)))]); + if (!Components.length) throw new Error("Check is dist have packages"); + Release.Components = Components.join(" "); - const createPackagesHash = distConfig["apt-config"]?.enableHash ?? repositoryConfig["apt-config"]?.enableHash ?? true; - if (createPackagesHash) { - ReleaseLines.push("Acquire-By-Hash: no"); - const hashs = (await Promise.all(archs.map(async arch => Promise.all(suites.map(async suite => { - const [gzip, xz, raw] = await Promise.all([packInfos.createPackages({compress: "gzip", dist, arch, suite}), packInfos.createPackages({compress: "xz", dist, arch, suite}), packInfos.createPackages({dist, arch, suite})]); - return { - gz: { - sha256: { - file: `${suite}/binary-${arch}/Packages.gz`, - size: gzip.size, - hash: gzip.sha256 - }, - sha1: { - file: `${suite}/binary-${arch}/Packages.gz`, - size: gzip.size, - hash: gzip.sha1 - }, - md5: { - file: `${suite}/binary-${arch}/Packages.gz`, - size: gzip.size, - hash: gzip.md5 - } + // Description + + // Sum's + const enableHash = Boolean(packageConfig["apt-config"]?.enableHash ?? packagesArray.find(x => x.aptConfig?.enableHash)?.aptConfig?.enableHash); + if (enableHash) { + Release.SHA256 = []; + Release.SHA1 = []; + Release.MD5sum = []; + const files = await Promise.all(Archs.map(async Arch => Promise.all(Components.map(async Component => { + const {SUMs} = await createPackages(dist, Component, Arch); + return [ + { + file: `${Component}/binary-${Arch}/Packages`, + hash: await SUMs.raw }, - xz: { - sha256: { - file: `${suite}/binary-${arch}/Packages.xz`, - size: xz.size, - hash: xz.sha256 - }, - sha1: { - file: `${suite}/binary-${arch}/Packages.xz`, - size: xz.size, - hash: xz.sha1 - }, - md5: { - file: `${suite}/binary-${arch}/Packages.xz`, - size: xz.size, - hash: xz.md5 - } + { + file: `${Component}/binary-${Arch}/Packages.gz`, + hash: await SUMs.gzip }, - raw: { - sha256: { - file: `${suite}/binary-${arch}/Packages`, - size: raw.size, - hash: raw.sha256 - }, - sha1: { - file: `${suite}/binary-${arch}/Packages`, - size: raw.size, - hash: raw.sha1 - }, - md5: { - file: `${suite}/binary-${arch}/Packages`, - size: raw.size, - hash: raw.md5 - } + { + file: `${Component}/binary-${Arch}/Packages.xz`, + hash: await SUMs.lzma } - }; - }))))).flat(2); + ] + })))).then(f => f.flat(3)); - const sha256 = hashs.map(hash => hash.raw.sha256).concat(hashs.map(hash => hash.gz.sha256)).concat(hashs.map(hash => hash.xz.sha256)); - if (sha256.length > 0) ReleaseLines.push(`SHA256:${sha256.sort().map((hash) => `\n ${hash.hash} ${hash.size} ${hash.file}`).join("")}`); - - const sha1 = hashs.map(hash => hash.raw.sha1).concat(hashs.map(hash => hash.gz.sha1)).concat(hashs.map(hash => hash.xz.sha1)); - if (sha1.length > 0) ReleaseLines.push(`SHA1:${sha1.sort().map((hash) => `\n ${hash.hash} ${hash.size} ${hash.file}`).join("")}`); - - const md5 = hashs.map(hash => hash.raw.md5).concat(hashs.map(hash => hash.gz.md5)).concat(hashs.map(hash => hash.xz.md5)); - if (md5.length > 0) ReleaseLines.push(`MD5Sum:${md5.sort().map((hash) => `\n ${hash.hash} ${hash.size} ${hash.file}`).join("")}`); + files.forEach(({file, hash}) => { + if (hash.hash.sha256) (Release.SHA256 as string[]).push(`${hash.hash.sha256} ${hash.size} ${file}`); + if (hash.hash.sha1) (Release.SHA1 as string[]).push(`${hash.hash.sha1} ${hash.size} ${file}`); + if (hash.hash.md5) (Release.MD5sum as string[]).push(`${hash.hash.md5} ${hash.size} ${file}`); + }); } - return ReleaseLines.join("\n"); + return Object.keys(Release).reduce((old, key) => { + if (Array.isArray(Release[key])) old.push(`${key}:\n ${(Release[key] as string[]).join("\n ")}`); + else old.push(`${key}: ${Release[key]}`); + return old; + }, []).join("\n"); } - app.get("/dists/(./)?:dist/Release", (req, res, next) => createReleaseV1(req.params.dist).then((data) => res.setHeader("Content-Type", "text/plain").send(data)).catch(next)); - app.get("/dists/(./)?:dist/InRelease", (req, res, next) => { - const Key = repositoryConfig["apt-config"]?.pgpKey; - if (!Key) return res.status(404).json({error: "No PGP key found"}); + app.get("/dists/(./)?:dist/Release", ({params: {dist}}, res, next) => createRelease(dist).then(release => res.setHeader("Content-Type", "text/plain").send(release)).catch(next)); + + const pgpKey = packageConfig["apt-config"]?.pgpKey; + app.get("/dists/(./)?:dist/inRelease", async (req, res, next) => { + if (!pgpKey) return res.status(404).json({error: "No PGP key found"}); return Promise.resolve().then(async () => { - const privateKey = Key.passphrase ? await openpgp.decryptKey({privateKey: await openpgp.readPrivateKey({ armoredKey: Key.private }), passphrase: Key.passphrase}) : await openpgp.readPrivateKey({ armoredKey: Key.private }); - const Release = await createReleaseV1(req.params.dist); + const privateKey = pgpKey.passphrase ? await openpgp.decryptKey({privateKey: await openpgp.readPrivateKey({ armoredKey: pgpKey.private }), passphrase: pgpKey.passphrase}) : await openpgp.readPrivateKey({ armoredKey: pgpKey.private }); + const Release = await createRelease(req.params.dist); return res.setHeader("Content-Type", "text/plain").send(await openpgp.sign({ signingKeys: privateKey, format: "armored", @@ -213,238 +176,27 @@ export default async function main(configPath: string) { })); }).catch(next); }); - app.get("/dists/(./)?:dist/Release.gpg", (req, res, next) => { - const Key = repositoryConfig["apt-config"]?.pgpKey; - if (!Key) return res.status(404).json({error: "No PGP key found"}); + app.get("/dists/(./)?:dist/Release.gpg", async (req, res, next) => { + if (!pgpKey) return res.status(404).json({error: "No PGP key found"}); return Promise.resolve().then(async () => { - const privateKey = Key.passphrase ? await openpgp.decryptKey({privateKey: await openpgp.readPrivateKey({ armoredKey: Key.private }), passphrase: Key.passphrase}) : await openpgp.readPrivateKey({ armoredKey: Key.private }); - const Release = await createReleaseV1(req.params.dist); + const privateKey = pgpKey.passphrase ? await openpgp.decryptKey({privateKey: await openpgp.readPrivateKey({ armoredKey: pgpKey.private }), passphrase: pgpKey.passphrase}) : await openpgp.readPrivateKey({ armoredKey: pgpKey.private }); + const Release = await createRelease(req.params.dist); return res.setHeader("Content-Type", "text/plain").send(await openpgp.sign({ signingKeys: privateKey, message: await openpgp.createMessage({text: Release}), })); }).catch(next); }); - - // 404 handler - app.use((_req, res) => { - res.status(404).json({error: "Not found"}); + // Public key + if (pgpKey) app.get(["/public_key", "/public.gpg"], async ({res}) => { + if (!pgpKey) return res.status(400).json({error: "This repository no sign Packages files"}); + const pubKey = (await openpgp.readKey({ armoredKey: pgpKey.public })).armor(); + return res.setHeader("Content-Type", "application/pgp-keys").send(pubKey); }); - // Error handler - app.use((err, _req, res, _next) => { - console.error(err); - res.status(500).json({ - error: err?.message||err, - stack: err?.stack?.split("\n"), - }); - }); - - // Listen HTTP server - const port = process.env.PORT ?? repositoryConfig["apt-config"].portListen ?? 0; - app.listen(port, function () {return console.log(`apt-repo listening at http://localhost:${this.address().port}`);}); - - // Loading and update packages - let cronJobs: CronJob[] = []; - const waitPromises: Promise[] = []; - const saveFile = repositoryConfig["apt-config"]?.saveFiles; - const rootPool = repositoryConfig["apt-config"]?.poolPath; - for (const dist in repositoryConfig.repositories) { - const targets = repositoryConfig.repositories[dist].targets; - for (const repository of targets) { - const update = async () => { - if (repository.from === "mirror") { - return Promise.all(Object.keys(repository.dists).map(async distName => { - const distInfo = repository.dists[distName]; - const packagesData = distInfo.suites ? await Promise.all(distInfo.suites.map(async suite => getPackages(repository.uri, {dist: distName, suite}))).then(U => U.flat()) : await getPackages(repository.uri, {dist: distName}); - return packagesData.forEach(({Package: control}) => { - const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); - const getStream = async () => { - if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); - if (saveFile) { - const mainPath = path.resolve(filePool, ".."); - if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); - const fileStream = await httpRequest.pipeFetch(control.Filename); - fileStream.pipe(createWriteStream(filePool)); - return fileStream; - } - return httpRequest.pipeFetch(control.Filename); - } - return packInfos.addPackage(dist, repository.suite ?? "main", {repositoryConfig: repository, control, getStream}); - }); - })); - } else if (repository.from === "oci") { - const registry = await DockerRegistry.Manifest.Manifest(repository.image, repository.platfom_target); - return registry.layersStream((data) => { - if (!(["gzip", "gz", "tar"]).some(ends => data.layer.mediaType.endsWith(ends))) return data.next(); - data.stream.pipe(tar.list({ - async onentry(entry) { - if (!entry.path.endsWith(".deb")) return null; - const control = await DebianPackage.extractControl(entry as any); - const suite = repository.suite ?? "main"; - packInfos.addPackage(dist, suite, { - repositoryConfig: repository, - control, - async getStream() { - const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); - if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); - return new Promise((done, reject) => registry.blobLayerStream(data.layer.digest).then(stream => { - stream.on("error", reject); - stream.pipe(tar.list({ - async onentry(getEntry) { - if (getEntry.path !== entry.path) return null; - if (saveFile) { - const mainPath = path.resolve(filePool, ".."); - if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); - entry.pipe(createWriteStream(filePool)); - } - return done(getEntry as any); - } - // @ts-ignore - }).on("error", reject)); - }).catch(reject)); - } - }); - } - })); - }); - } else if (repository.from === "github_release") { - if (repository.tags) { - const release = await Promise.all(repository.tags.map(async releaseTag => httpRequestGithub.getRelease({ - owner: repository.owner, - repository: repository.repository, - token: repository.token, - releaseTag, - }))); - return Promise.all(release.map(async release => Promise.all(release.assets.map(async ({browser_download_url, name}) => { - if (!name.endsWith(".deb")) return null; - const control = await DebianPackage.extractControl(await httpRequest.pipeFetch(browser_download_url)); - const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); - const getStream = async () => { - if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); - if (saveFile) { - const mainPath = path.resolve(filePool, ".."); - if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); - const fileStream = await httpRequest.pipeFetch(browser_download_url); - fileStream.pipe(createWriteStream(filePool)); - return fileStream; - } - return httpRequest.pipeFetch(browser_download_url); - } - return packInfos.addPackage(dist, repository.suite ?? release.tag_name, {repositoryConfig: repository, control, getStream}); - })))).then(data => data.flat(2).filter(Boolean)); - } - const release = await httpRequestGithub.getRelease({owner: repository.owner, repository: repository.repository, token: repository.token, peer: repository.assetsLimit, all: false}); - return Promise.all(release.map(async release => Promise.all(release.assets.map(async ({browser_download_url, name}) => { - if (!name.endsWith(".deb")) return null; - const control = await DebianPackage.extractControl(await httpRequest.pipeFetch(browser_download_url)); - const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); - const getStream = async () => { - if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); - if (saveFile) { - const mainPath = path.resolve(filePool, ".."); - if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); - const fileStream = await httpRequest.pipeFetch(browser_download_url); - fileStream.pipe(createWriteStream(filePool)); - return fileStream; - } - return httpRequest.pipeFetch(browser_download_url); - } - return packInfos.addPackage(dist, repository.suite ?? release.tag_name, {repositoryConfig: repository, control, getStream}); - })))).then(data => data.flat(2).filter(Boolean)); - } else if (repository.from === "github_tree") { - const { tree } = await httpRequestGithub.githubTree(repository.owner, repository.repository, repository.tree); - const filtedTree = tree.filter(({path: remotePath}) => { - if (repository.path) return repository.path.some(repoPath => { - if (!remotePath.startsWith("/")) remotePath = "/" + remotePath; - if (typeof repoPath === "string") { - if (!repoPath.startsWith("/")) repoPath = "/" + repoPath; - return remotePath.startsWith(repoPath); - } - return false; - }); - return true; - }).filter(({path, type}) => path.endsWith(".deb") && type === "blob"); - return Promise.all(filtedTree.map(async ({path: filePath}) => { - const downloadUrl = `https://raw.githubusercontent.com/${repository.owner}/${repository.repository}/${repository.tree}/${filePath}`; - const control = await DebianPackage.extractControl(await httpRequest.pipeFetch(downloadUrl)); - const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); - const getStream = async () => { - if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); - if (saveFile) { - const mainPath = path.resolve(filePool, ".."); - if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); - const fileStream = await httpRequest.pipeFetch(downloadUrl); - fileStream.pipe(createWriteStream(filePool)); - return fileStream; - } - return httpRequest.pipeFetch(downloadUrl); - } - return packInfos.addPackage(dist, repository.suite ?? "main", {repositoryConfig: repository, control, getStream}); - })); - } else if (repository.from === "google_drive") { - const client_id = repository.appSettings.client_id; - const client_secret = repository.appSettings.client_secret; - const token = repository.appSettings.token; - const googleDriver = await coreUtils.googleDriver.GoogleDriver(client_id, client_secret, { - token, - async authCallback(url, token) { - if (url) console.log("Please visit this url to auth google driver: %s", url); - else console.log("Google driver auth success, please save token to config file, token: %s", token); - }, - }); - const files = (repository.folderId ? (await Promise.all(repository.folderId.map(async folderId => await googleDriver.listFiles(folderId)))).flat() : await googleDriver.listFiles()); - return Promise.all(files.filter(({name, isTrashedFile}) => !isTrashedFile && name.endsWith(".deb")).map(async fileData => { - const control = await DebianPackage.extractControl(await googleDriver.getFileStream(fileData.id)); - const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); - const getStream = async () => { - if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); - if (saveFile) { - const mainPath = path.resolve(filePool, ".."); - if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); - const fileStream = await googleDriver.getFileStream(fileData.id); - fileStream.pipe(createWriteStream(filePool)); - return fileStream; - } - return googleDriver.getFileStream(fileData.id); - } - return packInfos.addPackage(dist, repository.suite ?? "main", {repositoryConfig: repository, control, getStream}); - })); - } else if (repository.from === "oracle_bucket") { - const oracleBucket = await coreUtils.oracleBucket(repository.region as any, repository.bucketName, repository.bucketNamespace, repository.auth); - return Promise.all((await oracleBucket.fileList()).filter(({name}) => name.endsWith(".deb")).map(async fileData => { - const control = await DebianPackage.extractControl(await oracleBucket.getFileStream(fileData.name)); - const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); - const getStream = async () => { - if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); - if (saveFile) { - const mainPath = path.resolve(filePool, ".."); - if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); - const fileStream = await oracleBucket.getFileStream(fileData.name); - fileStream.pipe(createWriteStream(filePool)); - return fileStream; - } - return oracleBucket.getFileStream(fileData.name); - } - return packInfos.addPackage(dist, repository.suite ?? "main", {repositoryConfig: repository, control, getStream}); - })); - } - return null; - } - waitPromises.push(update().then(() => { - const cron = (repository.cronRefresh ?? []).map((cron) => new CronJob(cron, update)); - cron.forEach((cron) => cron.start()); - cronJobs.push(...cron); - }).catch(console.error)); - } - } - // watch config file changes - watchFile(configPath, async () => { - console.info("Config file changed, reloading config and update packages..."); - repositoryConfig = await getConfig(configPath); - cronJobs.forEach((cron) => cron.stop()); - cronJobs = []; - }); - // await Promise.all(waitPromises); - return app; -} + return { + app, + packageManeger, + packageConfig + }; +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index b5f5857..f3b83fc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,6 +6,8 @@ import yargs from "yargs"; import path from "node:path"; import repo from "./express_route.js"; import yaml from "yaml"; +import os from "node:os"; +import cluster from "node:cluster"; yargs(process.argv.slice(2)).version(false).help().demandCommand().strictCommands().alias("h", "help").option("cofig-path", { type: "string", @@ -84,12 +86,52 @@ yargs(process.argv.slice(2)).version(false).help().demandCommand().strictCommand }).parseSync(); const config = await getConfig(options.cofigPath); const base64 = Buffer.from(options.json ? JSON.stringify(config) : yaml.stringify(config)).toString("base64"); - if (options.output) return writeFile(options.output, base64).then(() => console.log("Saved to '%s'", options.output)); + if (options.output) return writeFile(options.output, "base64:"+base64).then(() => console.log("Saved to '%s'", options.output)); console.log("base64:%s", base64); }); -}).command("server", "Run HTTP serber", yargs => { +}).command("server", "Run HTTP serber", async yargs => { const options = yargs.parseSync(); const envs = Object.keys(process.env).filter(key => key.startsWith("APT_STREAM")); - if (envs.length > 0) return Promise.all(envs.map(async env => repo(`env:${env}`))); - return repo(options.cofigPath); + const { app, packageConfig, packageManeger } = await repo(envs.length > 0 ? `env:${envs[0]}` : options.cofigPath); + app.all("*", ({res}) => res.status(404).json({ + error: "Endpoint not exists", + message: "Endpoint not exists, check the documentation for more information" + })); + app.use((err, {}, res, {}) => { + console.error(err); + const stack: string = err?.stack ?? "No stack"; + res.status(500).json({ + error: "Internal Server Error", + message: "There was an error on our part, sorry for the inconvenience", + stack: { + forUser: "Create issue in apt-stream repository (https://github.com/Sirherobrine23/apt-stream/issues) with value of 'forDeveloper'", + forDeveloper: stack + }, + }); + }); + const port = process.env.PORT ?? packageConfig["apt-config"]?.portListen ?? 3000; + if (!(Boolean(process.env["DISABLE_CLUSTER"]))) { + if (cluster.isWorker) { + app.listen(port, function() {console.log("Apt Stream Port listen on %f", this.address()?.port)}); + return console.log("Worker %d running, PID: %f", cluster.worker?.id ?? "No ID", process.pid); + } + console.log("Master %f is running", process.pid); + os.cpus().forEach(() => cluster.fork()); + cluster.on("exit", (worker, code, signal: NodeJS.Signals) => { + if (signal === "SIGKILL") return console.log("Worker %d was killed", worker?.id ?? "No ID"); + else if (signal === "SIGTERM") return console.log("Worker %d was terminated", worker?.id ?? "No ID"); + else if (code ) + console.log("Worker %d died with code: %s, Signal: %s", worker?.id ?? "No ID", code, signal ?? "No Signal"); + }); + } else app.listen(port, function() {console.log("Apt Stream Port listen on %f", this.address()?.port)}); + + // large ram available + if (os.freemem() > 2 * 1024 * 1024 * 1024) return Promise.all(Object.keys(packageConfig.repositories).map(async distName => {const dist = packageConfig.repositories[distName]; return Promise.all(dist.targets.map(async target => packageManeger.loadRepository(distName, target, packageConfig["apt-config"], packageConfig).catch(console.error)));})).catch(console.error); + console.warn("Not enough RAM to load all repositories, loading one by one"); + for (const distName in packageConfig.repositories) { + const dist = packageConfig.repositories[distName]; + for (const target of dist.targets) { + await packageManeger.loadRepository(distName, target, packageConfig["apt-config"], packageConfig).catch(console.error); + } + } }).parseAsync(); \ No newline at end of file diff --git a/src/packagesData.ts b/src/packagesData.ts new file mode 100644 index 0000000..a8fa379 --- /dev/null +++ b/src/packagesData.ts @@ -0,0 +1,382 @@ +import coreUtils, { DebianPackage, DockerRegistry, extendFs, httpRequest, httpRequestGithub } from "@sirherobrine23/coreutils"; +import { createReadStream, createWriteStream, promises as fs } from "node:fs"; +import { MongoClient, ServerApiVersion, Filter } from "mongodb"; +import { apt_config, backendConfig, repository } from "./repoConfig.js"; +import { Readable } from "node:stream"; +import { getPackages } from "./mirror.js"; +import path from "node:path"; +import tar from "tar"; + +export type packageSave = { + dist: string, + suite: string, + repository: repository, + aptConfig?: apt_config, + control: DebianPackage.debianControl, + restoreFileStream?: { + from: repository["from"], + [key: string]: any, + }, + getFileStream: () => Promise, +}; + +export type packageManegerV2 = { + loadRepository: (distName: string, repo: repository, packageAptConfig?: apt_config, aptConfig?: backendConfig) => Promise, + getPackages: (dist?: string, suite?: string, Package?: string, Arch?: string, Version?: string) => Promise, + deletePackage: (repo: Partial) => Promise, + addPackage: (repo: packageSave) => Promise, +}; + +/** + * Maneger and Load packages to Database or internal object (Nodejs Heap Memory, if large data use Database) + * @returns + */ +export default async function packageManeger(config: backendConfig): Promise { + const partialConfig: Partial = {}; + + partialConfig.loadRepository = async function loadRepository(distName: string, repository: repository, packageAptConfig?: apt_config, aptConfig?: backendConfig) { + const saveFile = aptConfig["apt-config"]?.saveFiles ?? false; + const rootPool = aptConfig["apt-config"]?.poolPath ?? path.join(process.cwd(), "pool"); + if (repository.from === "mirror") { + return Promise.all(Object.keys(repository.dists).map(async distName => { + const distInfo = repository.dists[distName]; + const packagesData = distInfo.suites ? await Promise.all(distInfo.suites.map(async suite => getPackages(repository.uri, {dist: distName, suite}))).then(U => U.flat()) : await getPackages(repository.uri, {dist: distName}); + return packagesData.forEach(({Package: control}) => { + const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); + const getStream = async () => { + if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); + if (saveFile) { + const mainPath = path.resolve(filePool, ".."); + if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); + const fileStream = await httpRequest.pipeFetch(control.Filename); + fileStream.pipe(createWriteStream(filePool)); + return fileStream; + } + return httpRequest.pipeFetch(control.Filename); + } + return partialConfig.addPackage({ + dist: distName, + suite: repository.suite, + repository: repository, + control, + aptConfig: packageAptConfig ?? aptConfig["apt-config"], + getFileStream: getStream, + restoreFileStream: { + from: "mirror", + fileUrl: control.Filename, + } + }); + }); + })); + } else if (repository.from === "oci") { + const registry = await DockerRegistry.Manifest.Manifest(repository.image, repository.platfom_target); + return registry.layersStream((data) => { + if (!(["gzip", "gz", "tar"]).some(ends => data.layer.mediaType.endsWith(ends))) return data.next(); + data.stream.pipe(tar.list({ + async onentry(entry) { + if (!entry.path.endsWith(".deb")) return null; + const control = await DebianPackage.extractControl(entry as any); + const suite = repository.suite ?? "main"; + async function getStream() { + const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); + if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); + return new Promise((done, reject) => registry.blobLayerStream(data.layer.digest).then(stream => { + stream.on("error", reject); + stream.pipe(tar.list({ + async onentry(getEntry) { + if (getEntry.path !== entry.path) return null; + if (saveFile) { + const mainPath = path.resolve(filePool, ".."); + if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); + entry.pipe(createWriteStream(filePool)); + } + return done(getEntry as any); + } + // @ts-ignore + }).on("error", reject)); + }).catch(reject)); + } + return partialConfig.addPackage({ + dist: distName, + suite, + repository: repository, + control, + aptConfig: packageAptConfig ?? aptConfig["apt-config"], + getFileStream: getStream, + restoreFileStream: { + from: "oci", + digest: data.layer.digest, + path: entry.path, + } + }); + } + })); + }); + } else if (repository.from === "github_release") { + if (repository.tags) { + const release = await Promise.all(repository.tags.map(async releaseTag => httpRequestGithub.getRelease({ + owner: repository.owner, + repository: repository.repository, + token: repository.token, + releaseTag, + }))); + return Promise.all(release.map(async release => Promise.all(release.assets.map(async ({browser_download_url, name}) => { + if (!name.endsWith(".deb")) return null; + const control = await DebianPackage.extractControl(await httpRequest.pipeFetch(browser_download_url)); + const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); + const getStream = async () => { + if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); + if (saveFile) { + const mainPath = path.resolve(filePool, ".."); + if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); + const fileStream = await httpRequest.pipeFetch(browser_download_url); + fileStream.pipe(createWriteStream(filePool)); + return fileStream; + } + return httpRequest.pipeFetch(browser_download_url); + } + return partialConfig.addPackage({ + dist: distName, + suite: repository.suite ?? "main", + repository: repository, + control, + aptConfig: packageAptConfig ?? aptConfig["apt-config"], + getFileStream: getStream, + restoreFileStream: { + from: "github_release", + fileUrl: browser_download_url, + } + }); + })))).then(data => data.flat(2).filter(Boolean)); + } + const release = await httpRequestGithub.getRelease({owner: repository.owner, repository: repository.repository, token: repository.token, peer: repository.assetsLimit, all: false}); + return Promise.all(release.map(async release => Promise.all(release.assets.map(async ({browser_download_url, name}) => { + if (!name.endsWith(".deb")) return null; + const control = await DebianPackage.extractControl(await httpRequest.pipeFetch(browser_download_url)); + const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); + const getStream = async () => { + if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); + if (saveFile) { + const mainPath = path.resolve(filePool, ".."); + if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); + const fileStream = await httpRequest.pipeFetch(browser_download_url); + fileStream.pipe(createWriteStream(filePool)); + return fileStream; + } + return httpRequest.pipeFetch(browser_download_url); + } + return partialConfig.addPackage({ + dist: distName, + suite: repository.suite ?? "main", + repository: repository, + control, + aptConfig: packageAptConfig ?? aptConfig["apt-config"], + getFileStream: getStream, + restoreFileStream: { + from: "github_release", + fileUrl: browser_download_url, + } + }); + })))).then(data => data.flat(2).filter(Boolean)); + } else if (repository.from === "github_tree") { + const { tree } = await httpRequestGithub.githubTree(repository.owner, repository.repository, repository.tree); + const filtedTree = tree.filter(({path: remotePath}) => { + if (repository.path) return repository.path.some(repoPath => { + if (!remotePath.startsWith("/")) remotePath = "/" + remotePath; + if (typeof repoPath === "string") { + if (!repoPath.startsWith("/")) repoPath = "/" + repoPath; + return remotePath.startsWith(repoPath); + } + return false; + }); + return true; + }).filter(({path, type}) => path.endsWith(".deb") && type === "blob"); + return Promise.all(filtedTree.map(async ({path: filePath}) => { + const downloadUrl = `https://raw.githubusercontent.com/${repository.owner}/${repository.repository}/${repository.tree}/${filePath}`; + const control = await DebianPackage.extractControl(await httpRequest.pipeFetch(downloadUrl)); + const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); + const getStream = async () => { + if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); + if (saveFile) { + const mainPath = path.resolve(filePool, ".."); + if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); + const fileStream = await httpRequest.pipeFetch(downloadUrl); + fileStream.pipe(createWriteStream(filePool)); + return fileStream; + } + return httpRequest.pipeFetch(downloadUrl); + } + return partialConfig.addPackage({ + dist: distName, + suite: repository.suite ?? "main", + repository: repository, + control, + aptConfig: packageAptConfig ?? aptConfig["apt-config"], + getFileStream: getStream, + restoreFileStream: { + from: "github_tree", + fileUrl: downloadUrl, + } + }); + })); + } else if (repository.from === "google_drive") { + const client_id = repository.appSettings.client_id; + const client_secret = repository.appSettings.client_secret; + const token = repository.appSettings.token; + const googleDriver = await coreUtils.googleDriver.GoogleDriver(client_id, client_secret, { + token, + async authCallback(url, token) { + if (url) console.log("Please visit this url to auth google driver: %s", url); + else console.log("Google driver auth success, please save token to config file, token: %s", token); + }, + }); + const files = (repository.folderId ? (await Promise.all(repository.folderId.map(async folderId => await googleDriver.listFiles(folderId)))).flat() : await googleDriver.listFiles()); + return Promise.all(files.filter(({name, isTrashedFile}) => !isTrashedFile && name.endsWith(".deb")).map(async fileData => { + const control = await DebianPackage.extractControl(await googleDriver.getFileStream(fileData.id)); + const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); + const getStream = async () => { + if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); + if (saveFile) { + const mainPath = path.resolve(filePool, ".."); + if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); + const fileStream = await googleDriver.getFileStream(fileData.id); + fileStream.pipe(createWriteStream(filePool)); + return fileStream; + } + return googleDriver.getFileStream(fileData.id); + } + return partialConfig.addPackage({ + dist: distName, + suite: repository.suite ?? "main", + repository: repository, + control, + aptConfig: packageAptConfig ?? aptConfig["apt-config"], + getFileStream: getStream, + restoreFileStream: { + from: "google_drive", + fileId: fileData.id, + } + }); + })); + } else if (repository.from === "oracle_bucket") { + const oracleBucket = await coreUtils.oracleBucket(repository.region as any, repository.bucketName, repository.bucketNamespace, repository.auth); + return Promise.all((await oracleBucket.fileList()).filter(({name}) => name.endsWith(".deb")).map(async fileData => { + const control = await DebianPackage.extractControl(await oracleBucket.getFileStream(fileData.name)); + const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); + const getStream = async () => { + if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); + if (saveFile) { + const mainPath = path.resolve(filePool, ".."); + if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); + const fileStream = await oracleBucket.getFileStream(fileData.name); + fileStream.pipe(createWriteStream(filePool)); + return fileStream; + } + return oracleBucket.getFileStream(fileData.name); + } + return partialConfig.addPackage({ + dist: distName, + suite: repository.suite ?? "main", + repository: repository, + control, + aptConfig: packageAptConfig ?? aptConfig["apt-config"], + getFileStream: getStream, + restoreFileStream: { + from: "oracle_bucket", + fileName: fileData.name, + } + }); + })); + } + + throw new Error(`Unknown repository from: ${(repository as any)?.from ?? "undefined"}`); + } + + if (config["apt-config"]?.mongodb) { + // Connect to database + const mongoConfig = config["apt-config"].mongodb; + const mongoClient = await (new MongoClient(mongoConfig.uri, {serverApi: ServerApiVersion.v1})).connect(); + const collection = mongoClient.db(mongoConfig.db ?? "aptStream").collection(mongoConfig.collection ?? "packagesData"); + + // Add package to database + partialConfig.addPackage = async function addPackage(repo) { + const existsPackage = await collection.findOne({dist: repo.dist, suite: repo.suite, "control.Package": repo.control.Package, "control.Version": repo.control.Version, "control.Architecture": repo.control.Architecture}); + if (existsPackage) await partialConfig.deletePackage(repo); + await collection.insertOne(repo); + } + + // Delete package + partialConfig.deletePackage = async function deletePackage(repo) { + const packageDelete = await collection.findOneAndDelete({dist: repo.dist, suite: repo.suite, "control.Package": repo.control.Package, "control.Version": repo.control.Version, "control.Architecture": repo.control.Architecture}); + if (!packageDelete.value) throw new Error("Package not found!"); + return packageDelete.value; + } + + // Packages + function fixPackage(data: packageSave): packageSave { + if (!data.restoreFileStream) throw new Error("cannot restore file stream!"); + data.getFileStream = async function getFileStream() { + if (data.restoreFileStream.from === "github_release"|| data.restoreFileStream.from === "github_tree") return coreUtils.httpRequest.pipeFetch(data.restoreFileStream.url); + else if (data.restoreFileStream.from === "google_drive" && data.repository.from === "google_drive") { + const googleDriver = await coreUtils.googleDriver.GoogleDriver(data.repository.appSettings.client_id, data.repository.appSettings.client_secret, {token: data.repository.appSettings.token}); + return googleDriver.getFileStream(data.restoreFileStream.fileId); + } else if (data.restoreFileStream.from === "oracle_bucket" && data.repository.from === "oracle_bucket") { + const oracleBucket = await coreUtils.oracleBucket(data.repository.region as any, data.repository.bucketName, data.repository.bucketNamespace, data.repository.auth); + return oracleBucket.getFileStream(data.restoreFileStream.fileName); + } else if (data.restoreFileStream.from === "mirror" && data.repository.from === "mirror") return coreUtils.httpRequest.pipeFetch(data.restoreFileStream.url); + else if (data.restoreFileStream.from === "oci" && data.repository.from === "oci") { + const oci = await coreUtils.DockerRegistry(data.repository.image); + return new Promise((done, reject) => { + oci.blobLayerStream(data.restoreFileStream.digest).then((stream) => { + stream.pipe(tar.list({ + filter: (path) => path === data.restoreFileStream.fileName, + onentry: (entry) => done(entry as any) + })) + }).catch(reject); + }); + } + throw new Error("Cannot restore file stream!"); + } + return data; + } + partialConfig.getPackages = async function getPackages(dist, suite, Package, Arch, Version) { + const doc: Filter = {}; + if (dist) doc.dist = dist; + if (suite) doc.suite = suite; + if (Package) doc["control.Package"] = Package; + if (Arch) doc["control.Architecture"] = Arch; + if (Version) doc["control.Version"] = Version; + const packageInfo = await collection.find(doc).toArray(); + if (!packageInfo) throw new Error("Package not found!"); + return packageInfo.map(fixPackage); + } + } else { + // Internal Object + let packagesArray: packageSave[] = []; + + // Add package to array + partialConfig.addPackage = async function addPackage(repo) { + const existsPackage = packagesArray.find((x) => x.control.Package === repo.control.Package && x.control.Version === repo.control.Version && x.control.Architecture === repo.control.Architecture && x.dist === repo.dist && x.suite === repo.suite && x.repository === repo.repository); + if (existsPackage) await partialConfig.deletePackage(repo); + packagesArray.push(repo); + } + + // Delete package + partialConfig.deletePackage = async function deletePackage(repo) { + const index = packagesArray.findIndex((x) => x.control.Package === repo.control.Package && x.control.Version === repo.control.Version && x.control.Architecture === repo.control.Architecture && x.dist === repo.dist && x.suite === repo.suite && x.repository === repo.repository); + if (index === -1) throw new Error("Package not found!"); + const packageDelete = packagesArray.splice(index, 1); + return packageDelete.at(-1); + } + + // Packages + partialConfig.getPackages = async function getPackages(dist, suite, Package, Arch, Version) { + const packageInfo = packagesArray.filter(x => (!dist || x.dist === dist) && (!suite || x.suite === suite) && (!Package || x.control.Package === Package) && (!Arch || x.control.Architecture === Arch) && (!Version || x.control.Version === Version)); + if (!packageInfo.length) throw new Error("Package not found!"); + return packageInfo; + } + } + + // Return functions + return partialConfig as packageManegerV2; +} \ No newline at end of file diff --git a/src/repoConfig.ts b/src/repoConfig.ts index 85893a0..553f8ab 100644 --- a/src/repoConfig.ts +++ b/src/repoConfig.ts @@ -1,15 +1,8 @@ -import coreUtils, { DebianPackage, DockerRegistry, extendFs, extendsCrypto, httpRequest } from "@sirherobrine23/coreutils"; -import { createReadStream, createWriteStream } from "node:fs"; -import { MongoClient, ServerApiVersion } from "mongodb"; -import { Compressor as lzmaCompressor } from "lzma-native"; -import { Readable, Writable } from "node:stream"; -import { debianControl } from "@sirherobrine23/coreutils/src/deb.js"; -import { createGzip } from "node:zlib"; +import coreUtils, { DockerRegistry, extendFs, httpRequest } from "@sirherobrine23/coreutils"; import { format } from "node:util"; import yaml from "yaml"; import path from "node:path"; import fs from "node:fs/promises"; -import tar from "tar"; export type apt_config = { origin?: string, @@ -108,7 +101,6 @@ export async function saveConfig(filePath: string, config: backendConfig) { } export async function getConfig(config: string) { - const fixedConfig: backendConfig = {}; let configData: backendConfig, avaiableToDirname = true; if (config.startsWith("http")) { avaiableToDirname = false; @@ -136,15 +128,20 @@ export async function getConfig(config: string) { } } } else { - if (!await coreUtils.extendFs.exists(config)) throw new Error("config File not exists"); + if (!await coreUtils.extendFs.exists(config)) throw new Error("config File not exists, return "+JSON.stringify(config)); configData = yaml.parse(await fs.readFile(config, "utf8")); } - fixedConfig["apt-config"] = {}; + if (typeof configData !== "object") throw new Error("Invalid config file"); + + const fixedConfig: backendConfig = { + "apt-config": {}, + repositories: {} + }; if (configData["apt-config"]) { const rootData = configData["apt-config"]; fixedConfig["apt-config"].portListen = rootData.portListen ?? 3000; - fixedConfig["apt-config"].poolPath = rootData.poolPath ?? path.join(process.cwd(), "apt-stream"); fixedConfig["apt-config"].saveFiles = rootData.saveFiles ?? false; + if (rootData.poolPath) fixedConfig["apt-config"].poolPath = rootData.poolPath; if (fixedConfig["apt-config"].poolPath && !await extendFs.exists(fixedConfig["apt-config"].poolPath)) await fs.mkdir(fixedConfig["apt-config"].poolPath, {recursive: true}); if (rootData.codename) fixedConfig["apt-config"].codename = rootData.codename; if (rootData.origin) fixedConfig["apt-config"].origin = rootData.origin; @@ -288,308 +285,4 @@ export async function getConfig(config: string) { }); }); return fixedConfig; -} - -export type packageData = { - control: debianControl, - getStream: () => Readable|Promise, - repositoryConfig?: repository -} - -type distObject = { - [distribuition: string]: { - [suite: string]: { - [arch: string]: packageData[] - } - } -} - -type dbDist = { - control: debianControl, - repositoryConfig?: repository, - dist: string, - suite: string, - getfile: repository & {file: string, blobLayer?: string} -}; - -export class distManegerPackages { - public distribuitions: distObject = {}; - public mongoClinte?: MongoClient; - public internalDist: distObject = {}; - public config: backendConfig; - constructor(config: backendConfig) { - this.config = config; - if (config["apt-config"]?.mongodb) { - this.mongoClinte = new MongoClient(config["apt-config"]?.mongodb?.uri, { - serverApi: ServerApiVersion.v1, - }); - this.mongoClinte.connect(); - } - } - - async getPackages(dist?: string, suite?: string): Promise { - let repo: distObject = {}; - if (!this.mongoClinte) repo = this.distribuitions; - else { - if (dist && typeof dist !== "string") throw new Error("dist must be a string"); - if (suite && typeof suite !== "string") throw new Error("suite must be a string"); - const saveFile = this.config["apt-config"]?.saveFiles; - const rootPool = this.config["apt-config"]?.poolPath; - const collection = this.mongoClinte.db(this.config["apt-config"]?.mongodb?.db ?? "packages").collection(this.config["apt-config"]?.mongodb.collection ?? "packages"); - for (const dataDB of await collection.find({dist, suite}).toArray()) { - const repository = dataDB.getfile, control = dataDB.control; - if (dist && dist !== dataDB.dist) continue; - if (suite && suite !== dataDB.suite) continue; - async function getStream() { - if (repository.from === "mirror") { - const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); - if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); - return coreUtils.httpRequest.pipeFetch(dataDB.getfile.file); - } else if (repository.from === "oci") { - const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); - if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); - const registry = await coreUtils.DockerRegistry(repository.image, repository.platfom_target); - return new Promise((done, reject) => registry.blobLayerStream(dataDB.getfile.blobLayer).then(stream => { - stream.on("error", reject); - stream.pipe(tar.list({ - async onentry(getEntry) { - if (getEntry.path !== dataDB.getfile.file) return null; - if (saveFile) { - const mainPath = path.resolve(filePool, ".."); - if (!await extendFs.exists(mainPath)) await fs.mkdir(mainPath, {recursive: true}); - getEntry.pipe(createWriteStream(filePool)); - } - return done(getEntry as any); - } - // @ts-ignore - }).on("error", reject)); - }).catch(reject)); - } else if (repository.from === "github_release" || repository.from === "github_tree") { - const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); - if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); - return coreUtils.httpRequest.pipeFetch({ - url: dataDB.getfile.file, - headers: (repository.token ? {"Authorization": `token ${repository.token}`} : {}) - }) - } else if (repository.from === "google_drive") { - const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); - if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); - const client_id = repository.appSettings.client_id; - const client_secret = repository.appSettings.client_secret; - const token = repository.appSettings.token; - const googleDriver = await coreUtils.googleDriver.GoogleDriver(client_id, client_secret, { - token, - async authCallback(url, token) { - if (url) console.log("Please visit this url to auth google driver: %s", url); - else console.log("Google driver auth success, please save token to config file, token: %s", token); - }, - }); - return googleDriver.getFileStream(dataDB.getfile.file); - } else if (repository.from === "oracle_bucket") { - const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); - if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); - const oracleBucket = await coreUtils.oracleBucket(repository.region as any, repository.bucketName, repository.bucketNamespace, repository.auth); - return oracleBucket.getFileStream(dataDB.getfile.file); - } - - return null; - } - if (!repo[dataDB.dist]) repo[dataDB.dist] = {}; - if (!repo[dataDB.dist][dataDB.suite]) repo[dataDB.dist][dataDB.suite] = {}; - if (!repo[dataDB.dist][dataDB.suite][control.Architecture]) repo[dataDB.dist][dataDB.suite][control.Architecture] = []; - repo[dataDB.dist][dataDB.suite][control.Architecture].push({ - getStream, - repositoryConfig: dataDB.repositoryConfig, - control, - }); - console.log("add package %s %s %s %s", dataDB.dist, dataDB.suite, control.Architecture, control.Package); - }; - } - return repo; - } - - public async addDistribuition(distribuition: string) { - if (!this.distribuitions[distribuition]) this.distribuitions[distribuition] = {}; - return this.distribuitions[distribuition]; - } - public async addSuite(distribuition: string, suite: string) { - if (!this.distribuitions[distribuition][suite]) this.distribuitions[distribuition][suite] = {}; - return this.distribuitions[distribuition][suite]; - } - public async addArch(distribuition: string, suite: string, arch: string) { - if (!this.distribuitions[distribuition][suite][arch]) this.distribuitions[distribuition][suite][arch] = []; - return this.distribuitions[distribuition][suite][arch]; - } - - /** - * Register package in distribuition and suite - * - * @param distribuition - * @param suite - * @param arch - * @param control - * @param getStream - * @returns - */ - public async addPackage(distribuition: string, suite: string, packageData: packageData) { - const dist = await this.getPackages(distribuition, suite); - this.addDistribuition(distribuition); - this.addSuite(distribuition, suite); - this.addArch(distribuition, suite, packageData.control.Architecture); - const currentPackages = dist[distribuition]?.[suite]?.[packageData.control.Architecture] ?? []; - if (!this.mongoClinte) { - if (currentPackages.some(pkg => pkg.control.Package === packageData.control.Package)) { - if (currentPackages.some(pkg => pkg.control.Version === packageData.control.Version && pkg.control.Package === packageData.control.Package)) { - const index = currentPackages.findIndex(pkg => pkg.control.Version === packageData.control.Version && pkg.control.Package === packageData.control.Package); - return dist[distribuition][suite][packageData.control.Architecture][index] = packageData; - } - } - dist[distribuition][suite][packageData.control.Architecture].push(packageData); - } else { - const collection = this.mongoClinte.db(this.config["apt-config"]?.mongodb?.db ?? "packages").collection(this.config["apt-config"]?.mongodb.collection ?? "packages"); - const currentPackages = await collection.findOne({ - dist: distribuition, - suite, - cotrol: { - Package: packageData.control.Package, - Version: packageData.control.Version, - Architecture: packageData.control.Architecture, - } - }); - if (currentPackages) await collection.deleteOne(currentPackages); - await collection.insertOne({ - dist: distribuition, - suite, - control: packageData.control, - repository: packageData.repositoryConfig - }); - } - return packageData; - } - - public deletePackage(distribuition: string, suite: string, arch: string, packageName: string, version: string) { - if (!this.distribuitions[distribuition]) throw new Error("Distribuition not exists"); - if (!this.distribuitions[distribuition][suite]) throw new Error("Suite not exists"); - if (!this.distribuitions[distribuition][suite][arch]) throw new Error("Arch not exists"); - const index = this.distribuitions[distribuition][suite][arch].findIndex(pkg => pkg.control.Package === packageName && pkg.control.Version === version); - if (index === -1) throw new Error("Package not exists"); - const data = this.distribuitions[distribuition][suite][arch][index]; - this.distribuitions[distribuition][suite][arch].splice(index, 1); - return data; - } - - public async getDistribuition(distName: string) { - const dist = (await this.getPackages(distName))[distName]; - if (!dist) return null; - const suites = Object.keys(dist); - const suiteData = suites.map(suite => { - const Packages = Object.keys(dist[suite]).map(arch => dist[suite][arch].map(packageInfo => packageInfo.control)).flat(); - return { - Suite: suite, - Archs: Object.keys(dist[suite]), - Packages - }; - }); - - return { - dist: distName, - suites, - archs: [...(new Set(suiteData.map(suite => suite.Archs).flat()))], - suiteData, - }; - } - - public async getAllDistribuitions() { - const dist = await this.getPackages(); - return (await Promise.all(Object.keys(dist).map(dist => this.getDistribuition(dist)))).flat().filter(Boolean); - } - - public async getPackageInfo(info: {dist: string, suite?: string, arch?: string, packageName?: string, version?: string}) { - const packageDateObject: {[k: string]: {[l: string]: {[a: string]: DebianPackage.debianControl[]}}} = {}; - const distData = await this.getPackages(info.dist, info.suite); - for (const dist in distData) { - if (info.dist && info.dist !== dist) continue; - packageDateObject[dist] = {}; - for (const suite in distData[dist]) { - if (info.suite && info.suite !== suite) continue; - packageDateObject[dist][suite] = {}; - for (const arch in distData[dist][suite]) { - if (info.arch && info.arch !== arch) continue; - packageDateObject[dist][suite][arch] = distData[dist][suite][arch].map(pkg => pkg.control).filter(pkg => (!info.packageName || pkg.Package === info.packageName) && (!info.version || pkg.Version === info.version)); - } - } - } - - if (info.dist) { - const dist = packageDateObject[info.dist]; - if (info.suite) { - const suite = dist[info.suite]; - if (info.arch) { - const arch = suite[info.arch]; - if (info.packageName) return arch.find(pkg => pkg.Package === info.packageName && (!info.version || pkg.Version === info.version)); - return arch; - } - } - return dist; - } - return packageDateObject; - } - - public async getPackageStream(distribuition: string, suite: string, arch: string, packageName: string, version: string) { - const dist = (await this.getPackages(distribuition))[distribuition]; - if (!dist) throw new Error("Distribuition not exists"); - if (!dist[suite]) throw new Error("Suite not exists"); - if (!dist[suite][arch]) throw new Error("Arch not exists"); - const packageData = dist[suite][arch].find(pkg => pkg.control.Package === packageName && pkg.control.Version === version); - if (!packageData) throw new Error("Package not exists"); - return Promise.resolve(packageData.getStream()).then(stream => ({control: packageData.control, repository: packageData.repositoryConfig, stream})); - } - - public async createPackages(options?: {compress?: "gzip" | "xz", writeStream?: Writable, singlePackages?: boolean, dist?: string, package?: string, arch?: string, suite?: string}) { - const distribuition = await this.getPackages(options?.dist); - const rawWrite = new Readable({read(){}}); - let size = 0, addbreak = false, hash: ReturnType|undefined; - if (options?.compress === "gzip") { - const gzip = rawWrite.pipe(createGzip({level: 9})); - if (options?.writeStream) gzip.pipe(options.writeStream); - hash = extendsCrypto.createHashAsync("all", gzip); - gzip.on("data", (chunk) => size += chunk.length); - } else if (options?.compress === "xz") { - const lzma = rawWrite.pipe(lzmaCompressor()); - if (options?.writeStream) lzma.pipe(options.writeStream); - hash = extendsCrypto.createHashAsync("all", lzma); - lzma.on("data", (chunk) => size += chunk.length); - } else { - if (options?.writeStream) rawWrite.pipe(options.writeStream); - hash = extendsCrypto.createHashAsync("all", rawWrite); - rawWrite.on("data", (chunk) => size += chunk.length); - } - - for (const dist in distribuition) { - if (options?.dist && options.dist !== dist) continue; - const suites = distribuition[dist]; - for (const suite in suites) { - if (options?.suite && options.suite !== suite) continue; - const archs = suites[suite]; - for (const arch in archs) { - if (arch !== "all" && (options?.arch && options.arch !== arch)) continue; - const packages = archs[arch]; - for (const {control} of packages) { - if (!control.Size) continue; - if (!(control.SHA1 || control.SHA256 || control.MD5sum)) continue; - if (options?.package && options.package !== control.Package) continue; - if (addbreak) rawWrite.push("\n\n"); else addbreak = true; - control["Filename"] = poolLocationPackage(dist, suite, arch, control.Package, control.Version); - const Data = Object.keys(control).map(key => `${key}: ${control[key]}`); - rawWrite.push(Data.join("\n")); - if (options?.singlePackages) break; - } - } - } - } - - rawWrite.push(null); - if (hash) return hash.then(hash => ({...hash, size})); - return null; - } } \ No newline at end of file -- 2.45.2 From 943bf1f39aa0e9db7db286f3ac2d450108568c63 Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Tue, 10 Jan 2023 13:03:23 -0300 Subject: [PATCH 3/6] Update mirror and init remove Promise.all() --- Dockerfile | 1 - src/express_route.ts | 20 +++++++----- src/index.ts | 20 +++++++----- src/mirror.ts | 4 +-- src/packagesData.ts | 74 +++++++++++++++++++++++++++++++++++--------- src/repoConfig.ts | 5 ++- tsconfig.json | 4 ++- 7 files changed, 93 insertions(+), 35 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9341091..5498e68 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,5 +4,4 @@ COPY package*.json ./ RUN npm ci COPY . . RUN npm run build -ENV NODE_OPTIONS="--max_old_space_size=4096" ENTRYPOINT [ "node", "src/index.js", "server" ] \ No newline at end of file diff --git a/src/express_route.ts b/src/express_route.ts index 5a89bda..58c42a5 100644 --- a/src/express_route.ts +++ b/src/express_route.ts @@ -13,11 +13,13 @@ export default async function initApp(config: string) { const packageManeger = await package_maneger(packageConfig); const app = express(); app.disable("x-powered-by").disable("etag").use(express.json()).use(express.urlencoded({extended: true})).use((req, res, next) => { - res.json = data => res.setHeader("Content-Type", "application/json").send(JSON.stringify(data, null, 2)); - const cluserID = cluster.worker?.id ?? 0; - // [%s TIME STAMP, cluserID: %f]: Path: %s, Method: %s, IP: %s - console.log("[%s, cluserID: %f]: Path: %s, Method: %s, IP: %s", new Date().toISOString(), cluserID, req.path, req.method, req.ip); - res.on("close", () => console.log("[%s, cluserID: %f]: Path: %s, Method: %s, IP: %s, Status: %f", new Date().toISOString(), cluserID, req.path, req.method, req.ip, res.statusCode)); + res.json = data => { + Promise.resolve(data).then(data => res.setHeader("Content-Type", "application/json").send(JSON.stringify(data, null, 2))).catch(next); + return res; + }; + const cluserID = (cluster.worker?.id === 1 ? "Primary" : cluster.worker?.id) ?? "Primary"; + console.log("[%s, cluserID: %s]: Path: %s, Method: %s, IP: %s", new Date().toISOString(), cluserID, req.path, req.method, req.ip); + res.on("close", () => console.log("[%s, cluserID: %s]: Path: %s, Method: %s, IP: %s, Status: %f", new Date().toISOString(), cluserID, req.path, req.method, req.ip, res.statusCode)); next(); }); app.get("/pool/:dist/:suite/:package/:arch/:version/download.deb", async ({params: {dist, suite, package: packageName, arch, version}}, {writeHead}, next) => { @@ -55,6 +57,10 @@ export default async function initApp(config: string) { // Create Package, Package.gz and Package.xz async function createPackages(dist: string, suite: string, arch: string) { + if (!await packageManeger.existsDist(dist)) throw new Error("Distribution not exists"); + if (!await packageManeger.existsSuite(dist, suite)) throw new Error("Suite not exists"); + const packages = (await packageManeger.getPackages(dist, suite, undefined, arch)).concat(arch !== "all" ? await packageManeger.getPackages(dist, suite, undefined, "all") : []); + if (!packages.length) throw new Error("Check is dist or suite have packages"); let rawSize = 0, gzipSize = 0, lzmaSize = 0; const mainReadstream = new Readable({read(){}}), rawSUMs = coreUtils.extendsCrypto.createHashAsync("all", mainReadstream).then(hash => ({size: rawSize, hash})); const gzip = mainReadstream.pipe(createGzip()), gzipSUMs = coreUtils.extendsCrypto.createHashAsync("all", gzip).then(hash => ({size: gzipSize, hash})); @@ -63,8 +69,6 @@ export default async function initApp(config: string) { gzip.on("data", data => gzipSize += data.length); lzma.on("data", data => lzmaSize += data.length); - const packages = await packageManeger.getPackages(dist, suite, undefined, arch); - if (!packages.length) throw new Error("Check is dist or suite have packages"); let fist = true; for (const {control} of packages) { if (!(control.Size && (control.MD5sum || control.SHA256 || control.SHA1))) continue; @@ -93,8 +97,8 @@ export default async function initApp(config: string) { // Release async function createRelease(dist: string) { + if (!await packageManeger.existsDist(dist)) throw new Error("Dist exists"); const packagesArray = await packageManeger.getPackages(dist); - if (!packagesArray.length) throw new Error("Check is dist have packages"); const Release: {[key: string]: string|string[]} = {}; // Date diff --git a/src/index.ts b/src/index.ts index f3b83fc..aba3973 100644 --- a/src/index.ts +++ b/src/index.ts @@ -100,7 +100,7 @@ yargs(process.argv.slice(2)).version(false).help().demandCommand().strictCommand app.use((err, {}, res, {}) => { console.error(err); const stack: string = err?.stack ?? "No stack"; - res.status(500).json({ + res.status(400).json({ error: "Internal Server Error", message: "There was an error on our part, sorry for the inconvenience", stack: { @@ -112,21 +112,25 @@ yargs(process.argv.slice(2)).version(false).help().demandCommand().strictCommand const port = process.env.PORT ?? packageConfig["apt-config"]?.portListen ?? 3000; if (!(Boolean(process.env["DISABLE_CLUSTER"]))) { if (cluster.isWorker) { - app.listen(port, function() {console.log("Apt Stream Port listen on %f", this.address()?.port)}); - return console.log("Worker %d running, PID: %f", cluster.worker?.id ?? "No ID", process.pid); + console.log("Worker %d running, PID: %f", cluster.worker?.id ?? "No ID", process.pid); + app.listen(port, function() { + console.log("Work apt Stream Port listen on %f", this.address()?.port); + }); + return; } - console.log("Master %f is running", process.pid); + console.log("Work master, PID %f, starting workers ...", process.pid); os.cpus().forEach(() => cluster.fork()); - cluster.on("exit", (worker, code, signal: NodeJS.Signals) => { + cluster.on("error", console.error).on("exit", (worker, code, signal: NodeJS.Signals) => { + // if (process[Symbol.for("ts-node.register.instance")]) cluster.setupPrimary({/* Fix for ts-node */ execArgv: ["--loader", "ts-node/esm"]}); if (signal === "SIGKILL") return console.log("Worker %d was killed", worker?.id ?? "No ID"); + else if (signal === "SIGABRT") return console.log("Worker %d was aborted", worker?.id ?? "No ID"); else if (signal === "SIGTERM") return console.log("Worker %d was terminated", worker?.id ?? "No ID"); - else if (code ) console.log("Worker %d died with code: %s, Signal: %s", worker?.id ?? "No ID", code, signal ?? "No Signal"); - }); + }).on("online", worker => console.log("Worker %d is online", worker?.id ?? "No ID")); } else app.listen(port, function() {console.log("Apt Stream Port listen on %f", this.address()?.port)}); // large ram available - if (os.freemem() > 2 * 1024 * 1024 * 1024) return Promise.all(Object.keys(packageConfig.repositories).map(async distName => {const dist = packageConfig.repositories[distName]; return Promise.all(dist.targets.map(async target => packageManeger.loadRepository(distName, target, packageConfig["apt-config"], packageConfig).catch(console.error)));})).catch(console.error); + if (os.freemem() > 2 * 1024 * 1024 * 1024) await Promise.all(Object.keys(packageConfig.repositories).map(async distName => {const dist = packageConfig.repositories[distName]; return Promise.all(dist.targets.map(async target => packageManeger.loadRepository(distName, target, packageConfig["apt-config"], packageConfig).catch(console.error)));})).catch(console.error); console.warn("Not enough RAM to load all repositories, loading one by one"); for (const distName in packageConfig.repositories) { const dist = packageConfig.repositories[distName]; diff --git a/src/mirror.ts b/src/mirror.ts index f8dcb5e..c13cb50 100644 --- a/src/mirror.ts +++ b/src/mirror.ts @@ -91,14 +91,14 @@ export async function getPackages(uri: string, options: {dist: string, suite?: s reject(err); } }); - let data = ""; + let data: string; stream.pipe(new Writable({ final(callback) { done(); callback(); }, write(chunkR, encoding, callback) { - data = data + (encoding === "binary" ? chunkR.toString("utf8") : Buffer.from(chunkR).toString("utf8")); + data = (data ?? "") + (encoding === "binary" ? chunkR.toString("utf8") : Buffer.from(chunkR).toString("utf8")); data.split(/^\n/).forEach((v) => { if (v.trim()) { data = data.replace(v, ""); diff --git a/src/packagesData.ts b/src/packagesData.ts index a8fa379..7d34eda 100644 --- a/src/packagesData.ts +++ b/src/packagesData.ts @@ -2,8 +2,9 @@ import coreUtils, { DebianPackage, DockerRegistry, extendFs, httpRequest, httpRe import { createReadStream, createWriteStream, promises as fs } from "node:fs"; import { MongoClient, ServerApiVersion, Filter } from "mongodb"; import { apt_config, backendConfig, repository } from "./repoConfig.js"; +import { getPackages as mirror } from "./mirror.js"; import { Readable } from "node:stream"; -import { getPackages } from "./mirror.js"; +import cluster from "node:cluster"; import path from "node:path"; import tar from "tar"; @@ -25,6 +26,8 @@ export type packageManegerV2 = { getPackages: (dist?: string, suite?: string, Package?: string, Arch?: string, Version?: string) => Promise, deletePackage: (repo: Partial) => Promise, addPackage: (repo: packageSave) => Promise, + existsDist: (dist: string) => Promise, + existsSuite: (dist: string, suite: string) => Promise, }; /** @@ -38,10 +41,13 @@ export default async function packageManeger(config: backendConfig): Promise { - const distInfo = repository.dists[distName]; - const packagesData = distInfo.suites ? await Promise.all(distInfo.suites.map(async suite => getPackages(repository.uri, {dist: distName, suite}))).then(U => U.flat()) : await getPackages(repository.uri, {dist: distName}); - return packagesData.forEach(({Package: control}) => { + // Ingore fast load data for low ram memory + for (const repoDistName in repository.dists) { + const distInfo = repository.dists[repoDistName]; + const packagesData: Awaited> = []; + if (!distInfo.suites) await mirror(repository.uri, {dist: distName}).then(U => packagesData.push(...U)); + else for (const suite of distInfo.suites) await mirror(repository.uri, {dist: repoDistName, suite}).then(U => packagesData.push(...U)); + const partialPromises = packagesData.map(({Package: control}) => { const filePool = path.join(rootPool, control.Package.slice(0, 1), `${control.Package}_${control.Architecture}_${control.Version}.deb`); const getStream = async () => { if (saveFile && await extendFs.exists(filePool)) return createReadStream(filePool); @@ -56,7 +62,7 @@ export default async function packageManeger(config: backendConfig): Promise { @@ -298,18 +306,37 @@ export default async function packageManeger(config: backendConfig): Promise(mongoConfig.collection ?? "packagesData"); + // Drop collection + if (cluster.isPrimary) { + if (mongoConfig.dropCollention && await collection.findOne()) { + await collection.drop(); + console.log("Drop collection: %s", mongoConfig.collection ?? "packagesData"); + } + } + // Add package to database partialConfig.addPackage = async function addPackage(repo) { const existsPackage = await collection.findOne({dist: repo.dist, suite: repo.suite, "control.Package": repo.control.Package, "control.Version": repo.control.Version, "control.Architecture": repo.control.Architecture}); if (existsPackage) await partialConfig.deletePackage(repo); await collection.insertOne(repo); + console.log("Added '%s', version: %s, Arch: %s, in to %s/%s", repo.control.Package, repo.control.Version, repo.control.Architecture, repo.dist, repo.suite); } // Delete package partialConfig.deletePackage = async function deletePackage(repo) { - const packageDelete = await collection.findOneAndDelete({dist: repo.dist, suite: repo.suite, "control.Package": repo.control.Package, "control.Version": repo.control.Version, "control.Architecture": repo.control.Architecture}); - if (!packageDelete.value) throw new Error("Package not found!"); - return packageDelete.value; + const packageDelete = (await collection.findOneAndDelete({dist: repo.dist, suite: repo.suite, "control.Package": repo.control.Package, "control.Version": repo.control.Version, "control.Architecture": repo.control.Architecture}))?.value; + if (!packageDelete) throw new Error("Package not found!"); + console.info("Deleted '%s', version: %s, Arch: %s, from %s/%s", packageDelete.control.Package, packageDelete.control.Version, packageDelete.control.Architecture, packageDelete.dist, packageDelete.suite); + return packageDelete; + } + + // Exists + partialConfig.existsDist = async function existsDist(dist) { + return (await collection.findOne({dist})) ? true : false; + } + partialConfig.existsSuite = async function existsSuite(dist, suite) { + if (await partialConfig.existsDist(dist)) return (await collection.findOne({dist, suite})) ? true : false; + return false; } // Packages @@ -341,8 +368,14 @@ export default async function packageManeger(config: backendConfig): Promise = {}; - if (dist) doc.dist = dist; - if (suite) doc.suite = suite; + if (dist) { + if (!await partialConfig.existsDist(dist)) throw new Error("Distribution not found!"); + doc.dist = dist; + } + if (suite) { + if (!await partialConfig.existsSuite(dist, suite)) throw new Error("Suite/Component not found!"); + doc.suite = suite; + } if (Package) doc["control.Package"] = Package; if (Arch) doc["control.Architecture"] = Arch; if (Version) doc["control.Version"] = Version; @@ -359,18 +392,31 @@ export default async function packageManeger(config: backendConfig): Promise x.control.Package === repo.control.Package && x.control.Version === repo.control.Version && x.control.Architecture === repo.control.Architecture && x.dist === repo.dist && x.suite === repo.suite && x.repository === repo.repository); if (existsPackage) await partialConfig.deletePackage(repo); packagesArray.push(repo); + console.log("Added '%s', version: %s, Arch: %s, in to %s/%s", repo.control.Package, repo.control.Version, repo.control.Architecture, repo.dist, repo.suite); } // Delete package partialConfig.deletePackage = async function deletePackage(repo) { const index = packagesArray.findIndex((x) => x.control.Package === repo.control.Package && x.control.Version === repo.control.Version && x.control.Architecture === repo.control.Architecture && x.dist === repo.dist && x.suite === repo.suite && x.repository === repo.repository); if (index === -1) throw new Error("Package not found!"); - const packageDelete = packagesArray.splice(index, 1); - return packageDelete.at(-1); + const packageDelete = packagesArray.splice(index, 1).at(-1); + console.info("Deleted '%s', version: %s, Arch: %s, from %s/%s", packageDelete.control.Package, packageDelete.control.Version, packageDelete.control.Architecture, packageDelete.dist, packageDelete.suite); + return packageDelete; + } + + // Exists + partialConfig.existsDist = async function existsDist(dist) { + return packagesArray.find(x => x.dist === dist) ? true : false; + } + partialConfig.existsSuite = async function existsSuite(dist, suite) { + if (await partialConfig.existsDist(dist)) return packagesArray.find(x => x.dist === dist && x.suite === suite) ? true : false; + return false; } // Packages partialConfig.getPackages = async function getPackages(dist, suite, Package, Arch, Version) { + if (dist && !await partialConfig.existsDist(dist)) throw new Error("Distribution not found!"); + if (suite && !await partialConfig.existsSuite(dist, suite)) throw new Error("Suite/Component not found!"); const packageInfo = packagesArray.filter(x => (!dist || x.dist === dist) && (!suite || x.suite === suite) && (!Package || x.control.Package === Package) && (!Arch || x.control.Architecture === Arch) && (!Version || x.control.Version === Version)); if (!packageInfo.length) throw new Error("Package not found!"); return packageInfo; diff --git a/src/repoConfig.ts b/src/repoConfig.ts index 553f8ab..f43a43f 100644 --- a/src/repoConfig.ts +++ b/src/repoConfig.ts @@ -82,6 +82,8 @@ export type backendConfig = Partial<{ uri: string, db?: string, collection?: string, + /** On connect to database drop collection to run in empty data */ + dropCollention?: boolean } }, repositories: { @@ -165,7 +167,8 @@ export async function getConfig(config: string) { fixedConfig["apt-config"].mongodb = { uri: rootData.mongodb.uri, db: rootData.mongodb.db ?? "apt-stream", - collection: rootData.mongodb.collection ?? "packages" + collection: rootData.mongodb.collection ?? "packages", + dropCollention: Boolean(rootData.mongodb.dropCollention ?? false) }; } } diff --git a/tsconfig.json b/tsconfig.json index 18c4e04..49ab8ec 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,6 +21,8 @@ "src/**/*.test.ts" ], "ts-node": { - "esm": true + "esm": true, + "experimentalResolver": true, + "experimentalSpecifierResolution": "node" } } \ No newline at end of file -- 2.45.2 From 5e8e086f2caac0831264d3b967926c3996a36f86 Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Tue, 10 Jan 2023 13:10:26 -0300 Subject: [PATCH 4/6] Remove CodeQL --- .github/workflows/codeql.yml | 72 ------------------------------------ 1 file changed, 72 deletions(-) delete mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index f384349..0000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,72 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ "main" ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ "main" ] - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'javascript' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - - # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹī¸ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 - with: - category: "/language:${{matrix.language}}" -- 2.45.2 From cc3409ef4807675128649351c805d5aaf69bb4b0 Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Tue, 10 Jan 2023 19:09:29 -0300 Subject: [PATCH 5/6] add /dists and /dists/:distName endpoint --- .vscode/launch.json | 9 +++++---- Dockerfile | 6 +++--- package.json | 5 +++-- src/express_route.ts | 11 ++++++++--- src/index.ts | 35 ++++++++++++++++++++++++----------- src/packagesData.ts | 40 +++++++++++++++++++++++++++++++--------- 6 files changed, 74 insertions(+), 32 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index e63506e..29cf248 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,10 +11,11 @@ "internalConsoleOptions": "openOnSessionStart", "skipFiles": ["/**", "node_modules/**"], "cwd": "${workspaceRoot}", - "runtimeExecutable": "ts-node", - "args": ["src/index.ts", "server"], - "env": { - "DISABLE_CLUSTER": "true" + "runtimeExecutable": "node", + "args": ["src/index.js", "server", "--cpus=0"], + "preLaunchTask": { + "type": "npm", + "script": "build" } } ] diff --git a/Dockerfile b/Dockerfile index 5498e68..b9ba240 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ -FROM node:latest +FROM node:lts-alpine WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . -RUN npm run build -ENTRYPOINT [ "node", "src/index.js", "server" ] \ No newline at end of file +RUN npm run build && npm link +ENTRYPOINT [ "apt-stream", "server" ] \ No newline at end of file diff --git a/package.json b/package.json index e0e1ab0..df4c0b4 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,9 @@ "apt-stream": "./src/index.js" }, "scripts": { - "start": "ts-node src/index.ts", - "build": "tsc" + "start": "npm run build && node ./src/index.js", + "dev": "npm run build && node --inspect ./src/index.js server --cpu=0", + "build": "tsc --build --clean && tsc" }, "devDependencies": { "@types/express": "^4.17.15", diff --git a/src/express_route.ts b/src/express_route.ts index 58c42a5..0bfb29b 100644 --- a/src/express_route.ts +++ b/src/express_route.ts @@ -22,12 +22,12 @@ export default async function initApp(config: string) { res.on("close", () => console.log("[%s, cluserID: %s]: Path: %s, Method: %s, IP: %s, Status: %f", new Date().toISOString(), cluserID, req.path, req.method, req.ip, res.statusCode)); next(); }); - app.get("/pool/:dist/:suite/:package/:arch/:version/download.deb", async ({params: {dist, suite, package: packageName, arch, version}}, {writeHead}, next) => { + app.get("/pool/:dist/:suite/:package/:arch/:version/download.deb", async ({params: {dist, suite, package: packageName, arch, version}}, res, next) => { try { const data = (await packageManeger.getPackages(dist, suite, packageName, arch, version))?.at(-1); if (!data) return next(new Error("Not Found")); const fileStream = await data.getFileStream(); - fileStream.pipe(writeHead(200, { + fileStream.pipe(res.writeHead(200, { "Content-Type": "application/x-debian-package", "Content-Length": data.control.Size, "Content-Disposition": `attachment; filename="${packageName}_${version}_${arch}.deb"`, @@ -55,6 +55,10 @@ export default async function initApp(config: string) { return old; }, {}))).catch(next)); + // Dists info + app.get("/dists", ({}, res, next) => packageManeger.getDists().then(data => res.json(data)).catch(next)); + app.get("/dists/:dist", ({params: {dist}}, res, next) => packageManeger.getDistInfo(dist).then(data => res.json(data)).catch(next)); + // Create Package, Package.gz and Package.xz async function createPackages(dist: string, suite: string, arch: string) { if (!await packageManeger.existsDist(dist)) throw new Error("Distribution not exists"); @@ -74,7 +78,7 @@ export default async function initApp(config: string) { if (!(control.Size && (control.MD5sum || control.SHA256 || control.SHA1))) continue; if (fist) fist = false; else mainReadstream.push("\n\n"); control.Filename = `pool/${dist}/${suite}/${control.Package}/${control.Architecture}/${control.Version}/download.deb`; - mainReadstream.push(Object.keys(control).map(key => mainReadstream.push(`${key}: ${control[key]}`)).join("\n")); + mainReadstream.push(Object.keys(control).map(key => `${key}: ${control[key]}`).join("\n")); } mainReadstream.push(null); @@ -89,6 +93,7 @@ export default async function initApp(config: string) { } }; } + app.get("/dists/(./)?:dist/:suite/binary-:arch/Packages(.(xz|gz)|)", async ({params: {dist, suite, arch}, path: reqPath}, res, next) => createPackages(dist, suite, arch).then(packages => { if (reqPath.endsWith(".gz")) return packages.gzip.pipe(res); else if (reqPath.endsWith(".xz")) return packages.lzma.pipe(res); diff --git a/src/index.ts b/src/index.ts index aba3973..afa3d7f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -90,9 +90,17 @@ yargs(process.argv.slice(2)).version(false).help().demandCommand().strictCommand console.log("base64:%s", base64); }); }).command("server", "Run HTTP serber", async yargs => { - const options = yargs.parseSync(); - const envs = Object.keys(process.env).filter(key => key.startsWith("APT_STREAM")); - const { app, packageConfig, packageManeger } = await repo(envs.length > 0 ? `env:${envs[0]}` : options.cofigPath); + const options = yargs.option("cpus", { + type: "number", + default: os.cpus().length/2, + alias: "C", + demandOption: false, + description: "Number of cpus to use in Cluster" + }).parseSync(); + console.log("Starting server..."); + process.on("unhandledRejection", err => console.error(err)); + process.on("uncaughtException", err => console.error(err)); + const { app, packageConfig, packageManeger } = await repo(Object.keys(process.env).find(key => key.startsWith("APT_STREAM")) ? `env:${Object.keys(process.env).find(key => key.startsWith("APT_STREAM"))}` : options.cofigPath); app.all("*", ({res}) => res.status(404).json({ error: "Endpoint not exists", message: "Endpoint not exists, check the documentation for more information" @@ -110,7 +118,7 @@ yargs(process.argv.slice(2)).version(false).help().demandCommand().strictCommand }); }); const port = process.env.PORT ?? packageConfig["apt-config"]?.portListen ?? 3000; - if (!(Boolean(process.env["DISABLE_CLUSTER"]))) { + if (options.cpus > 1) { if (cluster.isWorker) { console.log("Worker %d running, PID: %f", cluster.worker?.id ?? "No ID", process.pid); app.listen(port, function() { @@ -119,23 +127,28 @@ yargs(process.argv.slice(2)).version(false).help().demandCommand().strictCommand return; } console.log("Work master, PID %f, starting workers ...", process.pid); - os.cpus().forEach(() => cluster.fork()); - cluster.on("error", console.error).on("exit", (worker, code, signal: NodeJS.Signals) => { + for (let i = 0; i < options.cpus; i++) cluster.fork({...process.env, workNumber: i}); + cluster.on("error", err => { + console.log(err?.stack ?? String(err)); + // process.exit(1); + }).on("exit", (worker, code, signal: NodeJS.Signals) => { // if (process[Symbol.for("ts-node.register.instance")]) cluster.setupPrimary({/* Fix for ts-node */ execArgv: ["--loader", "ts-node/esm"]}); if (signal === "SIGKILL") return console.log("Worker %d was killed", worker?.id ?? "No ID"); else if (signal === "SIGABRT") return console.log("Worker %d was aborted", worker?.id ?? "No ID"); else if (signal === "SIGTERM") return console.log("Worker %d was terminated", worker?.id ?? "No ID"); console.log("Worker %d died with code: %s, Signal: %s", worker?.id ?? "No ID", code, signal ?? "No Signal"); + cluster.fork(); }).on("online", worker => console.log("Worker %d is online", worker?.id ?? "No ID")); - } else app.listen(port, function() {console.log("Apt Stream Port listen on %f", this.address()?.port)}); + } else { + console.warn("Running without cluster, this is not recommended for production"); + app.listen(port, function() {console.log("Apt Stream Port listen on %f", this.address()?.port)}); + } - // large ram available - if (os.freemem() > 2 * 1024 * 1024 * 1024) await Promise.all(Object.keys(packageConfig.repositories).map(async distName => {const dist = packageConfig.repositories[distName]; return Promise.all(dist.targets.map(async target => packageManeger.loadRepository(distName, target, packageConfig["apt-config"], packageConfig).catch(console.error)));})).catch(console.error); - console.warn("Not enough RAM to load all repositories, loading one by one"); for (const distName in packageConfig.repositories) { const dist = packageConfig.repositories[distName]; for (const target of dist.targets) { - await packageManeger.loadRepository(distName, target, packageConfig["apt-config"], packageConfig).catch(console.error); + await packageManeger.loadRepository(distName, target, packageConfig["apt-config"], packageConfig).catch(err => console.error(String(err))); + console.log("Complete load repository '%s'", distName); } } }).parseAsync(); \ No newline at end of file diff --git a/src/packagesData.ts b/src/packagesData.ts index 7d34eda..ceae5c3 100644 --- a/src/packagesData.ts +++ b/src/packagesData.ts @@ -7,6 +7,7 @@ import { Readable } from "node:stream"; import cluster from "node:cluster"; import path from "node:path"; import tar from "tar"; +import { format } from "node:util"; export type packageSave = { dist: string, @@ -28,6 +29,13 @@ export type packageManegerV2 = { addPackage: (repo: packageSave) => Promise, existsDist: (dist: string) => Promise, existsSuite: (dist: string, suite: string) => Promise, + getDists: () => Promise, + getDistInfo: (dist: string) => Promise<{ + packagesCount: number, + arch: string[], + packagesName: string[], + suites: string[], + }>, }; /** @@ -36,6 +44,20 @@ export type packageManegerV2 = { */ export default async function packageManeger(config: backendConfig): Promise { const partialConfig: Partial = {}; + partialConfig.getDists = async function getDists() { + const packages = await partialConfig.getPackages(); + return [...new Set(packages.map(U => U.dist))]; + } + + partialConfig.getDistInfo = async function getDistInfo(dist: string) { + const packages = await partialConfig.getPackages(dist); + return { + packagesCount: packages.length, + packagesName: [...new Set(packages.map(U => U.control.Package))], + arch: [...new Set(packages.map(U => U.control.Architecture))], + suites: [...new Set(packages.map(U => U.suite))], + }; + } partialConfig.loadRepository = async function loadRepository(distName: string, repository: repository, packageAptConfig?: apt_config, aptConfig?: backendConfig) { const saveFile = aptConfig["apt-config"]?.saveFiles ?? false; @@ -71,7 +93,7 @@ export default async function packageManeger(config: backendConfig): Promise err); }); return Promise.all(partialPromises); @@ -154,7 +176,7 @@ export default async function packageManeger(config: backendConfig): Promise {}); })))).then(data => data.flat(2).filter(Boolean)); } const release = await httpRequestGithub.getRelease({owner: repository.owner, repository: repository.repository, token: repository.token, peer: repository.assetsLimit, all: false}); @@ -184,7 +206,7 @@ export default async function packageManeger(config: backendConfig): Promise {}); })))).then(data => data.flat(2).filter(Boolean)); } else if (repository.from === "github_tree") { const { tree } = await httpRequestGithub.githubTree(repository.owner, repository.repository, repository.tree); @@ -225,7 +247,7 @@ export default async function packageManeger(config: backendConfig): Promise {}); })); } else if (repository.from === "google_drive") { const client_id = repository.appSettings.client_id; @@ -264,7 +286,7 @@ export default async function packageManeger(config: backendConfig): Promise {}); })); } else if (repository.from === "oracle_bucket") { const oracleBucket = await coreUtils.oracleBucket(repository.region as any, repository.bucketName, repository.bucketNamespace, repository.auth); @@ -293,7 +315,7 @@ export default async function packageManeger(config: backendConfig): Promise {}); })); } @@ -317,7 +339,7 @@ export default async function packageManeger(config: backendConfig): Promise { @@ -390,7 +412,7 @@ export default async function packageManeger(config: backendConfig): Promise x.control.Package === repo.control.Package && x.control.Version === repo.control.Version && x.control.Architecture === repo.control.Architecture && x.dist === repo.dist && x.suite === repo.suite && x.repository === repo.repository); - if (existsPackage) await partialConfig.deletePackage(repo); + if (existsPackage) throw new Error("Package already exists!"); packagesArray.push(repo); console.log("Added '%s', version: %s, Arch: %s, in to %s/%s", repo.control.Package, repo.control.Version, repo.control.Architecture, repo.dist, repo.suite); } -- 2.45.2 From 4c759ca6d41da578b178fca78f94b78735c0d18f Mon Sep 17 00:00:00 2001 From: Matheus Sampaio Queiroga Date: Wed, 11 Jan 2023 00:13:09 -0300 Subject: [PATCH 6/6] add sort to packages and new options to config --- package-lock.json | 36 ++++++++++++++++++++ package.json | 2 ++ src/express_route.ts | 81 ++++++++++++++++++++++++++++++++++++-------- src/packagesData.ts | 17 ++++------ src/repoConfig.ts | 9 ++++- 5 files changed, 120 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index f6d45fd..bd110ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "lzma-native": "^8.0.6", "mongodb": "^4.13.0", "openpgp": "^5.5.0", + "semver": "^7.3.8", "tar": "^6.1.13", "yaml": "^2.2.1", "yargs": "^17.6.2" @@ -25,6 +26,7 @@ "@types/express": "^4.17.15", "@types/lzma-native": "^4.0.1", "@types/node": "^18.11.18", + "@types/semver": "^7.3.13", "@types/tar": "^6.1.3", "@types/yargs": "^17.0.19", "ts-node": "^10.9.1", @@ -1414,6 +1416,12 @@ "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/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", @@ -3204,6 +3212,20 @@ "node": ">=v12.22.7" } }, + "node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "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", @@ -4966,6 +4988,12 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "@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 + }, "@types/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", @@ -6280,6 +6308,14 @@ "xmlchars": "^2.2.0" } }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "requires": { + "lru-cache": "^6.0.0" + } + }, "send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", diff --git a/package.json b/package.json index df4c0b4..c3518af 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "@types/express": "^4.17.15", "@types/lzma-native": "^4.0.1", "@types/node": "^18.11.18", + "@types/semver": "^7.3.13", "@types/tar": "^6.1.3", "@types/yargs": "^17.0.19", "ts-node": "^10.9.1", @@ -49,6 +50,7 @@ "lzma-native": "^8.0.6", "mongodb": "^4.13.0", "openpgp": "^5.5.0", + "semver": "^7.3.8", "tar": "^6.1.13", "yaml": "^2.2.1", "yargs": "^17.6.2" diff --git a/src/express_route.ts b/src/express_route.ts index 0bfb29b..992a578 100644 --- a/src/express_route.ts +++ b/src/express_route.ts @@ -2,11 +2,14 @@ import { Compressor as lzmaCompress } from "lzma-native"; import { createGzip } from "node:zlib"; import { getConfig } from "./repoConfig.js"; import { Readable } from "node:stream"; -import package_maneger from "./packagesData.js"; +import package_maneger, { packageSave } from "./packagesData.js"; import coreUtils from "@sirherobrine23/coreutils"; import cluster from "node:cluster"; import express from "express"; import openpgp from "openpgp"; +import semver from "semver"; +import path from "node:path"; +import os from "node:os"; export default async function initApp(config: string) { const packageConfig = await getConfig(config); @@ -22,6 +25,18 @@ export default async function initApp(config: string) { res.on("close", () => console.log("[%s, cluserID: %s]: Path: %s, Method: %s, IP: %s, Status: %f", new Date().toISOString(), cluserID, req.path, req.method, req.ip, res.statusCode)); next(); }); + + // Info + app.get("/", ({res}) => { + return res.json({ + cluster: cluster.worker?.id ?? "No clustered", + cpuCores: os.cpus().length || "Unknown CPU core", + hostArch: process.arch, + hostPlatform: process.platform, + nodeVersion: process.version, + }); + }); + app.get("/pool/:dist/:suite/:package/:arch/:version/download.deb", async ({params: {dist, suite, package: packageName, arch, version}}, res, next) => { try { const data = (await packageManeger.getPackages(dist, suite, packageName, arch, version))?.at(-1); @@ -48,23 +63,59 @@ export default async function initApp(config: string) { return old; }, {}))).catch(next)); - app.get(["/", "/pool"], ({}, res, next) => packageManeger.getPackages().then(data => res.json(data.reduce((old, current) => { + app.get("/pool", ({}, res, next) => packageManeger.getPackages().then(data => res.json(data.reduce((old, current) => { if (!old[current.dist]) old[current.dist] = {}; if (!old[current.dist][current.suite]) old[current.dist][current.suite] = []; old[current.dist][current.suite].push(current.control); return old; }, {}))).catch(next)); + // Package list + app.get("/source(s)?(.list)?", async (req, res, next) => { + try { + const dists = await Promise.all(await packageManeger.getDists().then(data => data.map(dist => packageManeger.getDistInfo(dist).then(data => ({dist, data}))))); + res.set("Content-Type", "text/plain"); + const remotePath = path.posix.resolve(req.baseUrl + req.path, ".."), protocol = req.headers["x-forwarded-proto"] ?? req.protocol, hostname = process.env["RAILWAY_STATIC_URL"] ?? `${req.hostname}:${req.socket.localPort}`, host = packageConfig["apt-config"]?.sourcesHost ?? `${protocol}://${hostname}${remotePath}`; + const data = []; + for (const {dist, data: {suites}} of dists) data.push(`deb ${host} ${dist} ${suites.join(" ")}`); + return res.send(data.join("\n")); + } catch (err) {return next(err);} + }); + // Dists info app.get("/dists", ({}, res, next) => packageManeger.getDists().then(data => res.json(data)).catch(next)); app.get("/dists/:dist", ({params: {dist}}, res, next) => packageManeger.getDistInfo(dist).then(data => res.json(data)).catch(next)); + app.get("/dists/:dist/source(s)?(.list)?", async (req, res, next) => { + const {dist} = req.params; + try { + const data = await packageManeger.getDistInfo(dist); + res.set("Content-Type", "text/plain"); + const remotePath = path.posix.resolve(req.baseUrl + req.path, ".."), protocol = req.headers["x-forwarded-proto"] ?? req.protocol, hostname = process.env["RAILWAY_STATIC_URL"] ?? `${req.hostname}:${req.socket.localPort}`, host = packageConfig["apt-config"]?.sourcesHost ?? `${protocol}://${hostname}${remotePath}`; + return res.send(`deb ${host} ${dist} ${data.suites.join(" ")}`); + } catch (err) {return next(err);} + }); // Create Package, Package.gz and Package.xz - async function createPackages(dist: string, suite: string, arch: string) { - if (!await packageManeger.existsDist(dist)) throw new Error("Distribution not exists"); - if (!await packageManeger.existsSuite(dist, suite)) throw new Error("Suite not exists"); - const packages = (await packageManeger.getPackages(dist, suite, undefined, arch)).concat(arch !== "all" ? await packageManeger.getPackages(dist, suite, undefined, "all") : []); + function createPackages(packages: packageSave[], dist: string, suite: string) { if (!packages.length) throw new Error("Check is dist or suite have packages"); + const reduced = packages.reduce((old, current) => { + if (!old[current.control.Package]) old[current.control.Package] = []; + old[current.control.Package].push(current); + return old; + }, {} as {[packageName: string]: packageSave[]}); + packages = []; + Object.keys(reduced).forEach(packageName => { + reduced[packageName] = reduced[packageName].sort((b, a) => { + const aVersion = semver.valid(semver.coerce(a.control.Version) ?? ""), bVersion = semver.valid(semver.coerce(b.control.Version) ?? ""); + return semver.compare(aVersion, bVersion); + }); + if (!packageConfig["apt-config"]?.packagesOptions?.uniqueVersion) packages.push(...reduced[packageName]); + else { + const at = reduced[packageName].at(0); + if (at) packages.push(at); + } + }); + let rawSize = 0, gzipSize = 0, lzmaSize = 0; const mainReadstream = new Readable({read(){}}), rawSUMs = coreUtils.extendsCrypto.createHashAsync("all", mainReadstream).then(hash => ({size: rawSize, hash})); const gzip = mainReadstream.pipe(createGzip()), gzipSUMs = coreUtils.extendsCrypto.createHashAsync("all", gzip).then(hash => ({size: gzipSize, hash})); @@ -72,7 +123,6 @@ export default async function initApp(config: string) { mainReadstream.on("data", data => rawSize += data.length); gzip.on("data", data => gzipSize += data.length); lzma.on("data", data => lzmaSize += data.length); - let fist = true; for (const {control} of packages) { if (!(control.Size && (control.MD5sum || control.SHA256 || control.SHA1))) continue; @@ -94,12 +144,14 @@ export default async function initApp(config: string) { }; } - app.get("/dists/(./)?:dist/:suite/binary-:arch/Packages(.(xz|gz)|)", async ({params: {dist, suite, arch}, path: reqPath}, res, next) => createPackages(dist, suite, arch).then(packages => { - if (reqPath.endsWith(".gz")) return packages.gzip.pipe(res); - else if (reqPath.endsWith(".xz")) return packages.lzma.pipe(res); - else return packages.raw.pipe(res); - }).catch(next)); - + app.get("/dists/(./)?:dist/:suite/binary-:arch/Packages(.(xz|gz)|)", async ({params: {dist, suite, arch}, path: reqPath}, res, next) => { + try { + const packages = createPackages(await packageManeger.getPackages(dist, suite, undefined, arch), dist, suite); + if (reqPath.endsWith(".gz")) return packages.gzip.pipe(res); + else if (reqPath.endsWith(".xz")) return packages.lzma.pipe(res); + else return packages.raw.pipe(res); + } catch (err) {return next(err);} + }); // Release async function createRelease(dist: string) { if (!await packageManeger.existsDist(dist)) throw new Error("Dist exists"); @@ -140,7 +192,8 @@ export default async function initApp(config: string) { Release.SHA1 = []; Release.MD5sum = []; const files = await Promise.all(Archs.map(async Arch => Promise.all(Components.map(async Component => { - const {SUMs} = await createPackages(dist, Component, Arch); + const archPackages = packagesArray.filter(x => x.control.Architecture === Arch && x.suite === Component); + const {SUMs} = createPackages(archPackages, dist, Component); return [ { file: `${Component}/binary-${Arch}/Packages`, diff --git a/src/packagesData.ts b/src/packagesData.ts index ceae5c3..bcfb070 100644 --- a/src/packagesData.ts +++ b/src/packagesData.ts @@ -4,10 +4,10 @@ import { MongoClient, ServerApiVersion, Filter } from "mongodb"; import { apt_config, backendConfig, repository } from "./repoConfig.js"; import { getPackages as mirror } from "./mirror.js"; import { Readable } from "node:stream"; +import { format } from "node:util"; import cluster from "node:cluster"; import path from "node:path"; import tar from "tar"; -import { format } from "node:util"; export type packageSave = { dist: string, @@ -365,15 +365,12 @@ export default async function packageManeger(config: backendConfig): Promise { oci.blobLayerStream(data.restoreFileStream.digest).then((stream) => { diff --git a/src/repoConfig.ts b/src/repoConfig.ts index f43a43f..0791cf9 100644 --- a/src/repoConfig.ts +++ b/src/repoConfig.ts @@ -84,6 +84,9 @@ export type backendConfig = Partial<{ collection?: string, /** On connect to database drop collection to run in empty data */ dropCollention?: boolean + }, + packagesOptions?: { + uniqueVersion?: boolean, } }, repositories: { @@ -136,7 +139,11 @@ export async function getConfig(config: string) { if (typeof configData !== "object") throw new Error("Invalid config file"); const fixedConfig: backendConfig = { - "apt-config": {}, + "apt-config": { + packagesOptions: { + uniqueVersion: configData["apt-config"]?.packagesOptions?.uniqueVersion ?? false + } + }, repositories: {} }; if (configData["apt-config"]) { -- 2.45.2