From 9fd1b35d958523205444fecb7e9184072a1720e4 Mon Sep 17 00:00:00 2001 From: tamaina Date: Tue, 24 Jan 2023 01:34:14 +0000 Subject: [PATCH 01/20] fix TypeError: Cannot read properties of undefined (reading 'getLogger') --- packages/backend/src/core/activitypub/ApResolverService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/core/activitypub/ApResolverService.ts b/packages/backend/src/core/activitypub/ApResolverService.ts index 94bb6d6c55..ca7760af81 100644 --- a/packages/backend/src/core/activitypub/ApResolverService.ts +++ b/packages/backend/src/core/activitypub/ApResolverService.ts @@ -39,7 +39,7 @@ export class Resolver { private recursionLimit = 100, ) { this.history = new Set(); - this.logger = this.loggerService.getLogger('ap-resolve'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる + this.logger = this.loggerService?.getLogger('ap-resolve'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる this.undiciFetcher = this.httpRequestService.createFetcher({ maxRedirections: 0, }, {}, this.logger); From a2268a95be28d5591febed902c7682e4924b21f4 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 24 Jan 2023 14:10:26 +0900 Subject: [PATCH 02/20] :art: --- packages/frontend/src/components/MkNotification.vue | 2 +- packages/frontend/src/navbar.ts | 2 +- packages/frontend/src/pages/achievements.vue | 2 +- packages/frontend/src/pages/user/index.vue | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue index e992495a78..d8087eb23b 100644 --- a/packages/frontend/src/components/MkNotification.vue +++ b/packages/frontend/src/components/MkNotification.vue @@ -15,7 +15,7 @@ - + $i != null), to: '/my/achievements', }, diff --git a/packages/frontend/src/pages/achievements.vue b/packages/frontend/src/pages/achievements.vue index 14b8520696..effa2fcaf4 100644 --- a/packages/frontend/src/pages/achievements.vue +++ b/packages/frontend/src/pages/achievements.vue @@ -45,7 +45,7 @@ onDeactivated(() => { definePageMetadata({ title: i18n.ts.achievements, - icon: 'ti ti-military-award', + icon: 'ti ti-medal', }); diff --git a/packages/frontend/src/pages/user/index.vue b/packages/frontend/src/pages/user/index.vue index d63aa3a3a5..120f67d8a5 100644 --- a/packages/frontend/src/pages/user/index.vue +++ b/packages/frontend/src/pages/user/index.vue @@ -81,7 +81,7 @@ const headerTabs = $computed(() => user ? [{ }, ...(user.host == null ? [{ key: 'achievements', title: i18n.ts.achievements, - icon: 'ti ti-military-award', + icon: 'ti ti-medal', }] : []), ...($i && ($i.id === user.id)) || user.publicReactions ? [{ key: 'reactions', title: i18n.ts.reaction, From da274cd458c7a19507b9713b9063a5ce6d377674 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 24 Jan 2023 14:49:29 +0900 Subject: [PATCH 03/20] update deps --- gulpfile.js | 2 +- package.json | 6 +- packages/backend/package.json | 11 +- packages/frontend/package.json | 8 +- packages/frontend/src/style.scss | 6 +- pnpm-lock.yaml | 322 +++++++++++++------------------ 6 files changed, 150 insertions(+), 205 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index d567e8bf6c..a04ab4c1ad 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -20,7 +20,7 @@ gulp.task('copy:frontend:fonts', () => ); gulp.task('copy:frontend:tabler-icons', () => - gulp.src('./packages/frontend/node_modules/@tabler/icons/iconfont/**/*').pipe(gulp.dest('./built/_frontend_dist_/tabler-icons/')) + gulp.src('./packages/frontend/node_modules/@tabler/icons-webfont/**/*').pipe(gulp.dest('./built/_frontend_dist_/tabler-icons/')) ); gulp.task('copy:frontend:locales', cb => { diff --git a/package.json b/package.json index 279d3949c7..7b0d5093d1 100644 --- a/package.json +++ b/package.json @@ -54,12 +54,12 @@ "devDependencies": { "@types/gulp": "4.0.10", "@types/gulp-rename": "2.0.1", - "@typescript-eslint/eslint-plugin": "5.48.2", - "@typescript-eslint/parser": "5.48.2", + "@typescript-eslint/eslint-plugin": "5.49.0", + "@typescript-eslint/parser": "5.49.0", "cross-env": "7.0.3", "cypress": "12.3.0", "eslint": "^8.32.0", - "start-server-and-test": "1.15.2" + "start-server-and-test": "1.15.3" }, "optionalDependencies": { "@tensorflow/tfjs-core": "^4.2.0" diff --git a/packages/backend/package.json b/packages/backend/package.json index 565de4310d..6cac949ea7 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -19,8 +19,8 @@ "test-and-coverage": "pnpm jest-and-coverage" }, "optionalDependencies": { - "@tensorflow/tfjs": "^4.1.0", - "@tensorflow/tfjs-node": "4.1.0" + "@tensorflow/tfjs": "^4.2.0", + "@tensorflow/tfjs-node": "4.2.0" }, "dependencies": { "@bull-board/api": "^4.11.0", @@ -69,9 +69,8 @@ "ip-cidr": "3.0.11", "is-svg": "4.3.2", "js-yaml": "4.1.0", - "jsdom": "21.0.0", + "jsdom": "21.1.0", "json5": "2.2.3", - "json5-loader": "4.0.1", "jsonld": "8.1.0", "jsrsasign": "10.6.1", "mfm-js": "0.23.3", @@ -176,8 +175,8 @@ "@types/web-push": "3.3.2", "@types/websocket": "1.0.5", "@types/ws": "8.5.4", - "@typescript-eslint/eslint-plugin": "5.48.2", - "@typescript-eslint/parser": "5.48.2", + "@typescript-eslint/eslint-plugin": "5.49.0", + "@typescript-eslint/parser": "5.49.0", "cross-env": "7.0.3", "eslint": "8.32.0", "eslint-plugin-import": "2.27.5", diff --git a/packages/frontend/package.json b/packages/frontend/package.json index cdfa96ea82..da568a9eac 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -12,7 +12,7 @@ "@rollup/plugin-json": "6.0.0", "@rollup/pluginutils": "5.0.2", "@syuilo/aiscript": "0.12.2", - "@tabler/icons": "^1.118.0", + "@tabler/icons-webfont": "^2.0.0", "@vitejs/plugin-vue": "4.0.0", "@vue/compiler-sfc": "3.2.45", "autobind-decorator": "2.4.0", @@ -82,15 +82,15 @@ "@types/uuid": "9.0.0", "@types/websocket": "1.0.5", "@types/ws": "8.5.4", - "@typescript-eslint/eslint-plugin": "5.48.2", - "@typescript-eslint/parser": "5.48.2", + "@typescript-eslint/eslint-plugin": "5.49.0", + "@typescript-eslint/parser": "5.49.0", "@vue/runtime-core": "3.2.45", "cross-env": "7.0.3", "cypress": "12.3.0", "eslint": "8.32.0", "eslint-plugin-import": "2.27.5", "eslint-plugin-vue": "9.9.0", - "start-server-and-test": "1.15.2", + "start-server-and-test": "1.15.3", "vue-eslint-parser": "^9.1.0", "vue-tsc": "^1.0.24" } diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss index 4c6b764357..5d539a0f03 100644 --- a/packages/frontend/src/style.scss +++ b/packages/frontend/src/style.scss @@ -127,11 +127,11 @@ hr { } .ti { - vertical-align: -10%; - line-height: 0.9em; + vertical-align: -70%; + line-height: 0.5em; &:before { - font-size: 130%; + font-size: 150%; } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2551c4fd78..cdbbd3b825 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,8 +11,8 @@ importers: '@tensorflow/tfjs-core': ^4.2.0 '@types/gulp': 4.0.10 '@types/gulp-rename': 2.0.1 - '@typescript-eslint/eslint-plugin': 5.48.2 - '@typescript-eslint/parser': 5.48.2 + '@typescript-eslint/eslint-plugin': 5.49.0 + '@typescript-eslint/parser': 5.49.0 cross-env: 7.0.3 cypress: 12.3.0 eslint: ^8.32.0 @@ -23,7 +23,7 @@ importers: gulp-replace: 1.1.4 gulp-terser: 2.1.0 js-yaml: 4.1.0 - start-server-and-test: 1.15.2 + start-server-and-test: 1.15.3 typescript: 4.9.4 dependencies: execa: 5.1.1 @@ -39,12 +39,12 @@ importers: devDependencies: '@types/gulp': 4.0.10 '@types/gulp-rename': 2.0.1 - '@typescript-eslint/eslint-plugin': 5.48.2_caon6io6stgpr7lz2rtbhekxqy - '@typescript-eslint/parser': 5.48.2_7uibuqfxkfaozanbtbziikiqje + '@typescript-eslint/eslint-plugin': 5.49.0_iu322prlnwsygkcra5kbpy22si + '@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje cross-env: 7.0.3 cypress: 12.3.0 eslint: 8.32.0 - start-server-and-test: 1.15.2 + start-server-and-test: 1.15.3 packages/backend: specifiers: @@ -68,8 +68,8 @@ importers: '@swc/cli': ^0.1.59 '@swc/core': 1.3.27 '@swc/jest': 0.2.24 - '@tensorflow/tfjs': ^4.1.0 - '@tensorflow/tfjs-node': 4.1.0 + '@tensorflow/tfjs': ^4.2.0 + '@tensorflow/tfjs-node': 4.2.0 '@types/accepts': 1.3.5 '@types/archiver': 5.3.1 '@types/bcryptjs': 2.4.2 @@ -112,8 +112,8 @@ importers: '@types/web-push': 3.3.2 '@types/websocket': 1.0.5 '@types/ws': 8.5.4 - '@typescript-eslint/eslint-plugin': 5.48.2 - '@typescript-eslint/parser': 5.48.2 + '@typescript-eslint/eslint-plugin': 5.49.0 + '@typescript-eslint/parser': 5.49.0 accepts: ^1.3.8 ajv: 8.12.0 archiver: 5.3.1 @@ -150,9 +150,8 @@ importers: jest: 29.3.1 jest-mock: ^29.3.1 js-yaml: 4.1.0 - jsdom: 21.0.0 + jsdom: 21.1.0 json5: 2.2.3 - json5-loader: 4.0.1 jsonld: 8.1.0 jsrsasign: 10.6.1 mfm-js: 0.23.3 @@ -257,9 +256,8 @@ importers: ip-cidr: 3.0.11 is-svg: 4.3.2 js-yaml: 4.1.0 - jsdom: 21.0.0 + jsdom: 21.1.0 json5: 2.2.3 - json5-loader: 4.0.1 jsonld: 8.1.0 jsrsasign: 10.6.1 mfm-js: 0.23.3 @@ -268,7 +266,7 @@ importers: ms: 3.0.0-canary.1 nested-property: 4.0.0 nodemailer: 6.9.0 - nsfwjs: 2.4.2_@tensorflow+tfjs@4.1.0 + nsfwjs: 2.4.2_@tensorflow+tfjs@4.2.0 oauth: 0.10.0 os-utils: 0.0.14 parse5: 7.1.2 @@ -317,8 +315,8 @@ importers: ws: 8.12.0 xev: 3.0.2 optionalDependencies: - '@tensorflow/tfjs': 4.1.0_seedrandom@3.0.5 - '@tensorflow/tfjs-node': 4.1.0_seedrandom@3.0.5 + '@tensorflow/tfjs': 4.2.0_seedrandom@3.0.5 + '@tensorflow/tfjs-node': 4.2.0_seedrandom@3.0.5 devDependencies: '@redocly/openapi-core': 1.0.0-beta.120 '@swc/cli': 0.1.59_2w2rsb5d2wh3txrlxuiknf4vra @@ -366,11 +364,11 @@ importers: '@types/web-push': 3.3.2 '@types/websocket': 1.0.5 '@types/ws': 8.5.4 - '@typescript-eslint/eslint-plugin': 5.48.2_caon6io6stgpr7lz2rtbhekxqy - '@typescript-eslint/parser': 5.48.2_7uibuqfxkfaozanbtbziikiqje + '@typescript-eslint/eslint-plugin': 5.49.0_iu322prlnwsygkcra5kbpy22si + '@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje cross-env: 7.0.3 eslint: 8.32.0 - eslint-plugin-import: 2.27.5_2l6piu6guil2f63lj3qmhzbnn4 + eslint-plugin-import: 2.27.5_6savw6y3b7jng6f64kgkyoij64 execa: 6.1.0 jest: 29.3.1_@types+node@18.11.18 jest-mock: 29.3.1 @@ -383,7 +381,7 @@ importers: '@rollup/plugin-json': 6.0.0 '@rollup/pluginutils': 5.0.2 '@syuilo/aiscript': 0.12.2 - '@tabler/icons': ^1.118.0 + '@tabler/icons-webfont': ^2.0.0 '@types/escape-regexp': 0.0.1 '@types/glob': 8.0.1 '@types/gulp': 4.0.10 @@ -398,8 +396,8 @@ importers: '@types/uuid': 9.0.0 '@types/websocket': 1.0.5 '@types/ws': 8.5.4 - '@typescript-eslint/eslint-plugin': 5.48.2 - '@typescript-eslint/parser': 5.48.2 + '@typescript-eslint/eslint-plugin': 5.49.0 + '@typescript-eslint/parser': 5.49.0 '@vitejs/plugin-vue': 4.0.0 '@vue/compiler-sfc': 3.2.45 '@vue/runtime-core': 3.2.45 @@ -442,7 +440,7 @@ importers: sanitize-html: ^2.8.1 sass: 1.57.1 seedrandom: 3.0.5 - start-server-and-test: 1.15.2 + start-server-and-test: 1.15.3 strict-event-emitter-types: 2.0.0 stringz: 2.1.0 syuilo-password-strength: 0.0.1 @@ -468,7 +466,7 @@ importers: '@rollup/plugin-json': 6.0.0_rollup@3.10.1 '@rollup/pluginutils': 5.0.2_rollup@3.10.1 '@syuilo/aiscript': 0.12.2 - '@tabler/icons': 1.119.0 + '@tabler/icons-webfont': 2.0.0 '@vitejs/plugin-vue': 4.0.0_vite@4.0.4+vue@3.2.45 '@vue/compiler-sfc': 3.2.45 autobind-decorator: 2.4.0 @@ -537,15 +535,15 @@ importers: '@types/uuid': 9.0.0 '@types/websocket': 1.0.5 '@types/ws': 8.5.4 - '@typescript-eslint/eslint-plugin': 5.48.2_caon6io6stgpr7lz2rtbhekxqy - '@typescript-eslint/parser': 5.48.2_7uibuqfxkfaozanbtbziikiqje + '@typescript-eslint/eslint-plugin': 5.49.0_iu322prlnwsygkcra5kbpy22si + '@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje '@vue/runtime-core': 3.2.45 cross-env: 7.0.3 cypress: 12.3.0 eslint: 8.32.0 - eslint-plugin-import: 2.27.5_2l6piu6guil2f63lj3qmhzbnn4 + eslint-plugin-import: 2.27.5_6savw6y3b7jng6f64kgkyoij64 eslint-plugin-vue: 9.9.0_eslint@8.32.0 - start-server-and-test: 1.15.2 + start-server-and-test: 1.15.3 vue-eslint-parser: 9.1.0_eslint@8.32.0 vue-tsc: 1.0.24_typescript@4.9.4 @@ -2323,65 +2321,47 @@ packages: defer-to-connect: 2.0.1 dev: false - /@tabler/icons/1.119.0: - resolution: {integrity: sha512-Fk3Qq4w2SXcTjc/n1cuL5bccPkylrOMo7cYpQIf/yw6zP76LQV9dtLcHQUjFiUnaYuswR645CnURIhlafyAh9g==} - peerDependencies: - react: ^16.x || 17.x || 18.x - react-dom: ^16.x || 17.x || 18.x - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + /@tabler/icons-webfont/2.0.0: + resolution: {integrity: sha512-ApVVupe7WKZOJzK6T2iw15/k6VrTALsL5YzAmvgvcriuX8sRCKlcWaRljcf2sZMUrqyY+Yq6xiOpL2p2NHgQBQ==} + dependencies: + '@tabler/icons': 2.0.0 dev: false - /@tensorflow/tfjs-backend-cpu/4.1.0_npjwttp6o2hhjgfcmiedqvkgoa: - resolution: {integrity: sha512-NqxrwpYa/hXGaBa1RzxfHsLAsaniIZryhF5CxQM9uSp1ny8wUJMH+Mda/Y8+llS3weHug8JDAbAW2cabn8l84A==} + /@tabler/icons/2.0.0: + resolution: {integrity: sha512-ye93cVD8baCwJJ7J3GKlUM3FN+qW6lsEz4uaH8bHCwC8un2R4p+ZzyRNc/ksqVgMQJ4PKQ8xbYpv4dnbbRffsA==} + dev: false + + /@tensorflow/tfjs-backend-cpu/4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y: + resolution: {integrity: sha512-8HWg9J69m0Ovc6w8TVhhixMOcwA3t/NPXLblOA/sgJ+/JD5gsbpLWJk4QISQyb1RnpSVzw6PX3BSMTJU7hWVOg==} engines: {yarn: '>= 1.3.2'} peerDependencies: - '@tensorflow/tfjs-core': 4.1.0 + '@tensorflow/tfjs-core': 4.2.0 dependencies: - '@tensorflow/tfjs-core': 4.1.0 + '@tensorflow/tfjs-core': 4.2.0 '@types/seedrandom': 2.4.30 seedrandom: 3.0.5 dev: false - /@tensorflow/tfjs-backend-webgl/4.1.0_npjwttp6o2hhjgfcmiedqvkgoa: - resolution: {integrity: sha512-RDjwbFCPESjh+QTrTvKC623MO58gIqxQvtX3DfJLhlsSbnsvIpA5s1CXNJYzNVmFDia35mPYKmQQWvEvhl9weA==} + /@tensorflow/tfjs-backend-webgl/4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y: + resolution: {integrity: sha512-Qvf+hD5pSh+xi48kChSGzcDKJemkc4EKfoVVjuxl4k25ZUPwuEd7zZUAtinkLu1dzgHNyvePZY8k+9rVm59HJA==} engines: {yarn: '>= 1.3.2'} peerDependencies: - '@tensorflow/tfjs-core': 4.1.0 + '@tensorflow/tfjs-core': 4.2.0 dependencies: - '@tensorflow/tfjs-backend-cpu': 4.1.0_npjwttp6o2hhjgfcmiedqvkgoa - '@tensorflow/tfjs-core': 4.1.0 + '@tensorflow/tfjs-backend-cpu': 4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y + '@tensorflow/tfjs-core': 4.2.0 '@types/offscreencanvas': 2019.3.0 '@types/seedrandom': 2.4.30 '@types/webgl-ext': 0.0.30 seedrandom: 3.0.5 dev: false - /@tensorflow/tfjs-converter/4.1.0_npjwttp6o2hhjgfcmiedqvkgoa: - resolution: {integrity: sha512-pR4TSUI949a/5uUWjHga8xzxD7Y9AbobHJtCmg86Bldfl2GV8aibz87cNjpoO+iUhH8WZo1TOJy8GpM+MPT2DA==} + /@tensorflow/tfjs-converter/4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y: + resolution: {integrity: sha512-m+E2KJM6yGQdi8ElzWpChdD/JaqhWMCi9yK70v/ndkOaCL2q2UN48nYP2T5S15vkDvMIgzAQyZfh7hxQsMuvRQ==} peerDependencies: - '@tensorflow/tfjs-core': 4.1.0 + '@tensorflow/tfjs-core': 4.2.0 dependencies: - '@tensorflow/tfjs-core': 4.1.0 - dev: false - - /@tensorflow/tfjs-core/4.1.0: - resolution: {integrity: sha512-zERD4xtxNq3dV3+wPEMi2HWSV68FA8WucSAogzErp38/q98Byv9G1x8DhxQ+jowTcqN4srGWcBfK59jYwjlAvA==} - engines: {yarn: '>= 1.3.2'} - dependencies: - '@types/long': 4.0.2 - '@types/offscreencanvas': 2019.7.0 - '@types/seedrandom': 2.4.30 - '@types/webgl-ext': 0.0.30 - '@webgpu/types': 0.1.21 - long: 4.0.0 - node-fetch: 2.6.7 - seedrandom: 3.0.5 - transitivePeerDependencies: - - encoding + '@tensorflow/tfjs-core': 4.2.0 dev: false /@tensorflow/tfjs-core/4.2.0: @@ -2400,15 +2380,14 @@ packages: transitivePeerDependencies: - encoding dev: false - optional: true - /@tensorflow/tfjs-data/4.1.0_x6uqorr55fevqojbxncmwlp444: - resolution: {integrity: sha512-H6ef6NXPwi2xKYB6tVNZi5RqniMFpfUSlxG3q0BNxnyuyeCUSjJvHJFpah9hT/ysYjVdwspzh/I6B67h+lBchg==} + /@tensorflow/tfjs-data/4.2.0_qsavyspjcgrxymzlcpasp6rzxe: + resolution: {integrity: sha512-11t7Q+ikseduJgkd9iSeRrtor1aA3o5PVCFhC5yYvR3JLO55ic1+4Ryo0EJfhRoismS6zBUJrpzX4K0zlLbIfw==} peerDependencies: - '@tensorflow/tfjs-core': 4.1.0 + '@tensorflow/tfjs-core': 4.2.0 seedrandom: ^3.0.5 dependencies: - '@tensorflow/tfjs-core': 4.1.0 + '@tensorflow/tfjs-core': 4.2.0 '@types/node-fetch': 2.6.2 node-fetch: 2.6.7 seedrandom: 3.0.5 @@ -2417,21 +2396,21 @@ packages: - encoding dev: false - /@tensorflow/tfjs-layers/4.1.0_npjwttp6o2hhjgfcmiedqvkgoa: - resolution: {integrity: sha512-lzHNTZu1GwKl7hW5tt2COSpflE0m7xrsOf8AzRzpTDVJYYRx/x5ScMt/y//5jbRuaDOnb3EjT1FxWxwkD44/sg==} + /@tensorflow/tfjs-layers/4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y: + resolution: {integrity: sha512-SO0KTmCFOjrW+PlP9nKYXz07XGFq6uE7am9yH2bRaRPWpEeaKT/+k0C9vFMxI/GzRwY8AK4sLe4U+jE1mhYxGw==} peerDependencies: - '@tensorflow/tfjs-core': 4.1.0 + '@tensorflow/tfjs-core': 4.2.0 dependencies: - '@tensorflow/tfjs-core': 4.1.0 + '@tensorflow/tfjs-core': 4.2.0 dev: false - /@tensorflow/tfjs-node/4.1.0_seedrandom@3.0.5: - resolution: {integrity: sha512-2H7UJqVafuM9fbsMdzUkcfWLpH/owgvVHWES+gQsiueIqyOjpq6ZGSQLDxyuKtHP2D/8/kWeVIbnzAjnIRniuA==} + /@tensorflow/tfjs-node/4.2.0_seedrandom@3.0.5: + resolution: {integrity: sha512-dkyExfqTjMVDpKLBzHH2b7JWzGK+QORtYswvoNHbeHwx7kvYYRAQeiHxp+xrgry6LdbWfZs88IWCwNGoOiZ21w==} engines: {node: '>=8.11.0'} requiresBuild: true dependencies: '@mapbox/node-pre-gyp': 1.0.9 - '@tensorflow/tfjs': 4.1.0_seedrandom@3.0.5 + '@tensorflow/tfjs': 4.2.0_seedrandom@3.0.5 adm-zip: 0.5.10 google-protobuf: 3.21.2 https-proxy-agent: 2.2.4 @@ -2445,17 +2424,16 @@ packages: dev: false optional: true - /@tensorflow/tfjs/4.1.0_seedrandom@3.0.5: - resolution: {integrity: sha512-jlrJ6MIBos8NkmF+NHIWBnKVBGYJTG06QmW/A0vgyXwkp+3PgzX8TJ4MWIv/7oZr7g27zfY6dXA1OFzrrgvklA==} + /@tensorflow/tfjs/4.2.0_seedrandom@3.0.5: + resolution: {integrity: sha512-iZmtyGC9IJkx+TpFnkgDol8BHv2BU3zJ01HyNcuvnm1w1EqoNe+1n8bwvLzI/sxHMcHTqzuu7VugMaphryxE+A==} hasBin: true - requiresBuild: true dependencies: - '@tensorflow/tfjs-backend-cpu': 4.1.0_npjwttp6o2hhjgfcmiedqvkgoa - '@tensorflow/tfjs-backend-webgl': 4.1.0_npjwttp6o2hhjgfcmiedqvkgoa - '@tensorflow/tfjs-converter': 4.1.0_npjwttp6o2hhjgfcmiedqvkgoa - '@tensorflow/tfjs-core': 4.1.0 - '@tensorflow/tfjs-data': 4.1.0_x6uqorr55fevqojbxncmwlp444 - '@tensorflow/tfjs-layers': 4.1.0_npjwttp6o2hhjgfcmiedqvkgoa + '@tensorflow/tfjs-backend-cpu': 4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y + '@tensorflow/tfjs-backend-webgl': 4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y + '@tensorflow/tfjs-converter': 4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y + '@tensorflow/tfjs-core': 4.2.0 + '@tensorflow/tfjs-data': 4.2.0_qsavyspjcgrxymzlcpasp6rzxe + '@tensorflow/tfjs-layers': 4.2.0_tkoh6rxfpzme3tc2ndqbqcrg7y argparse: 1.0.10 chalk: 4.1.2 core-js: 3.27.1 @@ -2669,6 +2647,7 @@ packages: /@types/json-schema/7.0.11: resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} + dev: true /@types/json5/0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} @@ -2956,8 +2935,8 @@ packages: dev: true optional: true - /@typescript-eslint/eslint-plugin/5.48.2_caon6io6stgpr7lz2rtbhekxqy: - resolution: {integrity: sha512-sR0Gja9Ky1teIq4qJOl0nC+Tk64/uYdX+mi+5iB//MH8gwyx8e3SOyhEzeLZEFEEfCaLf8KJq+Bd/6je1t+CAg==} + /@typescript-eslint/eslint-plugin/5.49.0_iu322prlnwsygkcra5kbpy22si: + resolution: {integrity: sha512-IhxabIpcf++TBaBa1h7jtOWyon80SXPRLDq0dVz5SLFC/eW6tofkw/O7Ar3lkx5z5U6wzbKDrl2larprp5kk5Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 @@ -2967,10 +2946,10 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.48.2_7uibuqfxkfaozanbtbziikiqje - '@typescript-eslint/scope-manager': 5.48.2 - '@typescript-eslint/type-utils': 5.48.2_7uibuqfxkfaozanbtbziikiqje - '@typescript-eslint/utils': 5.48.2_7uibuqfxkfaozanbtbziikiqje + '@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje + '@typescript-eslint/scope-manager': 5.49.0 + '@typescript-eslint/type-utils': 5.49.0_7uibuqfxkfaozanbtbziikiqje + '@typescript-eslint/utils': 5.49.0_7uibuqfxkfaozanbtbziikiqje debug: 4.3.4 eslint: 8.32.0 ignore: 5.2.4 @@ -3003,8 +2982,8 @@ packages: - supports-color dev: true - /@typescript-eslint/parser/5.48.2_7uibuqfxkfaozanbtbziikiqje: - resolution: {integrity: sha512-38zMsKsG2sIuM5Oi/olurGwYJXzmtdsHhn5mI/pQogP+BjYVkK5iRazCQ8RGS0V+YLk282uWElN70zAAUmaYHw==} + /@typescript-eslint/parser/5.49.0_7uibuqfxkfaozanbtbziikiqje: + resolution: {integrity: sha512-veDlZN9mUhGqU31Qiv2qEp+XrJj5fgZpJ8PW30sHU+j/8/e5ruAhLaVDAeznS7A7i4ucb/s8IozpDtt9NqCkZg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -3013,9 +2992,9 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.48.2 - '@typescript-eslint/types': 5.48.2 - '@typescript-eslint/typescript-estree': 5.48.2_typescript@4.9.4 + '@typescript-eslint/scope-manager': 5.49.0 + '@typescript-eslint/types': 5.49.0 + '@typescript-eslint/typescript-estree': 5.49.0_typescript@4.9.4 debug: 4.3.4 eslint: 8.32.0 typescript: 4.9.4 @@ -3031,16 +3010,16 @@ packages: '@typescript-eslint/visitor-keys': 5.48.1 dev: true - /@typescript-eslint/scope-manager/5.48.2: - resolution: {integrity: sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==} + /@typescript-eslint/scope-manager/5.49.0: + resolution: {integrity: sha512-clpROBOiMIzpbWNxCe1xDK14uPZh35u4QaZO1GddilEzoCLAEz4szb51rBpdgurs5k2YzPtJeTEN3qVbG+LRUQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.48.2 - '@typescript-eslint/visitor-keys': 5.48.2 + '@typescript-eslint/types': 5.49.0 + '@typescript-eslint/visitor-keys': 5.49.0 dev: true - /@typescript-eslint/type-utils/5.48.2_7uibuqfxkfaozanbtbziikiqje: - resolution: {integrity: sha512-QVWx7J5sPMRiOMJp5dYshPxABRoZV1xbRirqSk8yuIIsu0nvMTZesKErEA3Oix1k+uvsk8Cs8TGJ6kQ0ndAcew==} + /@typescript-eslint/type-utils/5.49.0_7uibuqfxkfaozanbtbziikiqje: + resolution: {integrity: sha512-eUgLTYq0tR0FGU5g1YHm4rt5H/+V2IPVkP0cBmbhRyEmyGe4XvJ2YJ6sYTmONfjmdMqyMLad7SB8GvblbeESZA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '*' @@ -3049,8 +3028,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.48.2_typescript@4.9.4 - '@typescript-eslint/utils': 5.48.2_7uibuqfxkfaozanbtbziikiqje + '@typescript-eslint/typescript-estree': 5.49.0_typescript@4.9.4 + '@typescript-eslint/utils': 5.49.0_7uibuqfxkfaozanbtbziikiqje debug: 4.3.4 eslint: 8.32.0 tsutils: 3.21.0_typescript@4.9.4 @@ -3064,8 +3043,8 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/types/5.48.2: - resolution: {integrity: sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==} + /@typescript-eslint/types/5.49.0: + resolution: {integrity: sha512-7If46kusG+sSnEpu0yOz2xFv5nRz158nzEXnJFCGVEHWnuzolXKwrH5Bsf9zsNlOQkyZuk0BZKKoJQI+1JPBBg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -3090,8 +3069,8 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree/5.48.2_typescript@4.9.4: - resolution: {integrity: sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==} + /@typescript-eslint/typescript-estree/5.49.0_typescript@4.9.4: + resolution: {integrity: sha512-PBdx+V7deZT/3GjNYPVQv1Nc0U46dAHbIuOG8AZ3on3vuEKiPDwFE/lG1snN2eUB9IhF7EyF7K1hmTcLztNIsA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -3099,8 +3078,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.48.2 - '@typescript-eslint/visitor-keys': 5.48.2 + '@typescript-eslint/types': 5.49.0 + '@typescript-eslint/visitor-keys': 5.49.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -3111,17 +3090,17 @@ packages: - supports-color dev: true - /@typescript-eslint/utils/5.48.2_7uibuqfxkfaozanbtbziikiqje: - resolution: {integrity: sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==} + /@typescript-eslint/utils/5.49.0_7uibuqfxkfaozanbtbziikiqje: + resolution: {integrity: sha512-cPJue/4Si25FViIb74sHCLtM4nTSBXtLx1d3/QT6mirQ/c65bV8arBEebBJJizfq8W2YyMoPI/WWPFWitmNqnQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: '@types/json-schema': 7.0.11 '@types/semver': 7.3.13 - '@typescript-eslint/scope-manager': 5.48.2 - '@typescript-eslint/types': 5.48.2 - '@typescript-eslint/typescript-estree': 5.48.2_typescript@4.9.4 + '@typescript-eslint/scope-manager': 5.49.0 + '@typescript-eslint/types': 5.49.0 + '@typescript-eslint/typescript-estree': 5.49.0_typescript@4.9.4 eslint: 8.32.0 eslint-scope: 5.1.1 eslint-utils: 3.0.0_eslint@8.32.0 @@ -3139,11 +3118,11 @@ packages: eslint-visitor-keys: 3.3.0 dev: true - /@typescript-eslint/visitor-keys/5.48.2: - resolution: {integrity: sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==} + /@typescript-eslint/visitor-keys/5.49.0: + resolution: {integrity: sha512-v9jBMjpNWyn8B6k/Mjt6VbUS4J1GvUlR4x3Y+ibnP1z7y7V4n0WRz+50DY6+Myj0UaXVSuUlHohO+eZ8IJEnkg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.48.2 + '@typescript-eslint/types': 5.49.0 eslint-visitor-keys: 3.3.0 dev: true @@ -3386,14 +3365,6 @@ packages: ajv: 8.12.0 dev: false - /ajv-keywords/3.5.2_ajv@6.12.6: - resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} - peerDependencies: - ajv: ^6.9.1 - dependencies: - ajv: 6.12.6 - dev: false - /ajv/6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: @@ -3835,10 +3806,11 @@ packages: - debug dev: false - /axios/0.25.0_debug@4.3.4: - resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==} + /axios/0.27.2_debug@4.3.4: + resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==} dependencies: - follow-redirects: 1.15.2 + follow-redirects: 1.15.2_debug@4.3.4 + form-data: 4.0.0 transitivePeerDependencies: - debug dev: true @@ -3978,10 +3950,6 @@ packages: engines: {node: '>=0.6'} dev: false - /big.js/5.2.2: - resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} - dev: false - /bin-check/4.1.0: resolution: {integrity: sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==} engines: {node: '>=4'} @@ -5671,11 +5639,6 @@ packages: /emoji-regex/8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - /emojis-list/3.0.0: - resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} - engines: {node: '>= 4'} - dev: false - /encode-utf8/1.0.3: resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} dev: false @@ -6109,7 +6072,7 @@ packages: - supports-color dev: true - /eslint-module-utils/2.7.4_kvyj4idustix6trhy5lyssy2sq: + /eslint-module-utils/2.7.4_cnxxylyx37asr43xy64ejg3pwe: resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} engines: {node: '>=4'} peerDependencies: @@ -6130,7 +6093,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.48.2_7uibuqfxkfaozanbtbziikiqje + '@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje debug: 3.2.7 eslint: 8.32.0 eslint-import-resolver-node: 0.3.7 @@ -6200,7 +6163,7 @@ packages: - supports-color dev: true - /eslint-plugin-import/2.27.5_2l6piu6guil2f63lj3qmhzbnn4: + /eslint-plugin-import/2.27.5_6savw6y3b7jng6f64kgkyoij64: resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} engines: {node: '>=4'} peerDependencies: @@ -6210,7 +6173,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.48.2_7uibuqfxkfaozanbtbziikiqje + '@typescript-eslint/parser': 5.49.0_7uibuqfxkfaozanbtbziikiqje array-includes: 3.1.6 array.prototype.flat: 1.3.1 array.prototype.flatmap: 1.3.1 @@ -6218,7 +6181,7 @@ packages: doctrine: 2.1.0 eslint: 8.32.0 eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.7.4_kvyj4idustix6trhy5lyssy2sq + eslint-module-utils: 2.7.4_cnxxylyx37asr43xy64ejg3pwe has: 1.0.3 is-core-module: 2.11.0 is-glob: 4.0.3 @@ -7018,6 +6981,19 @@ packages: peerDependenciesMeta: debug: optional: true + dev: false + + /follow-redirects/1.15.2_debug@4.3.4: + resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dependencies: + debug: 4.3.4 + dev: true /for-each/0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -7069,7 +7045,6 @@ packages: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 - dev: false /formdata-polyfill/4.0.10: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} @@ -9125,8 +9100,8 @@ packages: engines: {node: '>=0.1.90'} dev: false - /jsdom/21.0.0: - resolution: {integrity: sha512-AIw+3ZakSUtDYvhwPwWHiZsUi3zHugpMEKlNPaurviseYoBqo0zBd3zqoUi3LPCNtPFlEP8FiW9MqCZdjb2IYA==} + /jsdom/21.1.0: + resolution: {integrity: sha512-m0lzlP7qOtthD918nenK3hdItSd2I+V3W9IrBcB36sqDwG+KnUs66IF5GY7laGWUnlM9vTsD0W1QwSEBYWWcJg==} engines: {node: '>=14'} peerDependencies: canvas: ^2.5.0 @@ -9199,17 +9174,6 @@ packages: /json-stringify-safe/5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - /json5-loader/4.0.1: - resolution: {integrity: sha512-c9viNZlZTz0MTIcf/4qvek5Dz1/PU3DNCB4PwUhlEZIV3qb1bSD6vQQymlV17/Wm6ncra1aCvmIPsuRj+KfEEg==} - engines: {node: '>= 10.13.0'} - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - dependencies: - json5: 2.2.3 - loader-utils: 2.0.4 - schema-utils: 3.1.1 - dev: false - /json5/1.0.1: resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==} hasBin: true @@ -9539,15 +9503,6 @@ packages: strip-bom: 2.0.0 dev: false - /loader-utils/2.0.4: - resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} - engines: {node: '>=8.9.0'} - dependencies: - big.js: 5.2.2 - emojis-list: 3.0.0 - json5: 2.2.3 - dev: false - /locate-path/5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -10403,13 +10358,13 @@ packages: set-blocking: 2.0.0 dev: false - /nsfwjs/2.4.2_@tensorflow+tfjs@4.1.0: + /nsfwjs/2.4.2_@tensorflow+tfjs@4.2.0: resolution: {integrity: sha512-i4Pp2yt59qPQgeZFyg3wXFBX52uSeu/hkDoqdZfe+sILRxNBUu0VDogj7Lmqak0GlrXviS/wLiVeIx40IDUu7A==} peerDependencies: '@tensorflow/tfjs': ^3.18.0 dependencies: '@nsfw-filter/gif-frames': 1.0.2 - '@tensorflow/tfjs': 4.1.0_seedrandom@3.0.5 + '@tensorflow/tfjs': 4.2.0_seedrandom@3.0.5 dev: false /nth-check/1.0.2: @@ -12262,15 +12217,6 @@ packages: xmlchars: 2.2.0 dev: false - /schema-utils/3.1.1: - resolution: {integrity: sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==} - engines: {node: '>= 10.13.0'} - dependencies: - '@types/json-schema': 7.0.11 - ajv: 6.12.6 - ajv-keywords: 3.5.2_ajv@6.12.6 - dev: false - /secure-json-parse/2.7.0: resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} dev: false @@ -12688,8 +12634,8 @@ packages: /standard-as-callback/2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} - /start-server-and-test/1.15.2: - resolution: {integrity: sha512-t5xJX04Hg7hqxiKHMJBz/n4zIMsE6G7hpAcerFAH+4Vh9le/LeyFcJERJM7WLiPygWF9TOg33oroJF1XOzJtYQ==} + /start-server-and-test/1.15.3: + resolution: {integrity: sha512-4GqkqghvUR9cJ8buvtgkyT0AHgVwCJ5EN8eDEhe9grTChGwWUxGm2nqfSeE9+0PZkLRdFqcwTwxVHe1y3ViutQ==} engines: {node: '>=6'} hasBin: true dependencies: @@ -12700,7 +12646,7 @@ packages: execa: 5.1.1 lazy-ass: 1.6.0 ps-tree: 1.2.0 - wait-on: 6.0.1_debug@4.3.4 + wait-on: 7.0.1_debug@4.3.4 transitivePeerDependencies: - supports-color dev: true @@ -13945,12 +13891,12 @@ packages: xml-name-validator: 4.0.0 dev: false - /wait-on/6.0.1_debug@4.3.4: - resolution: {integrity: sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==} - engines: {node: '>=10.0.0'} + /wait-on/7.0.1_debug@4.3.4: + resolution: {integrity: sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==} + engines: {node: '>=12.0.0'} hasBin: true dependencies: - axios: 0.25.0_debug@4.3.4 + axios: 0.27.2_debug@4.3.4 joi: 17.7.0 lodash: 4.17.21 minimist: 1.2.7 From b62894ff56b33f96dd979e309e015858cafcc33a Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 24 Jan 2023 15:02:16 +0900 Subject: [PATCH 04/20] use minified css --- packages/backend/src/server/web/views/base.pug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index b27bbcbce0..d05901baec 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -35,7 +35,7 @@ html link(rel='prefetch' href='https://xn--931a.moe/assets/info.jpg') link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.jpg') link(rel='prefetch' href='https://xn--931a.moe/assets/error.jpg') - link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.css') + link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css') link(rel='modulepreload' href=`/vite/${clientEntry.file}`) if !config.clientManifestExists From 6589e8a3909e42d8d116b06a608d5cfefd6aa7ed Mon Sep 17 00:00:00 2001 From: tamaina Date: Tue, 24 Jan 2023 15:54:14 +0900 Subject: [PATCH 05/20] Fix #9710 ? (#9712) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wip * update pnpm-lock * use our own DevNull * fix * deliverJobConcurrencyをmacSocketsで割ってソケット数にする --- .../backend/src/core/HttpRequestService.ts | 37 ++++++++++++++++--- .../src/core/activitypub/ApRequestService.ts | 7 +++- packages/backend/src/misc/dev-null.ts | 11 ++++++ pnpm-lock.yaml | 13 +------ 4 files changed, 49 insertions(+), 19 deletions(-) create mode 100644 packages/backend/src/misc/dev-null.ts diff --git a/packages/backend/src/core/HttpRequestService.ts b/packages/backend/src/core/HttpRequestService.ts index 3a70ac77f9..cd859d0023 100644 --- a/packages/backend/src/core/HttpRequestService.ts +++ b/packages/backend/src/core/HttpRequestService.ts @@ -134,9 +134,34 @@ export class UndiciFetcher { return res; } + @bindThis + public async request( + url: string | URL, + options: { dispatcher?: undici.Dispatcher } & Omit & Partial> = {}, + privateOptions: { noOkError?: boolean; bypassProxy?: boolean; } = { noOkError: false, bypassProxy: false }, + ): Promise { + const res = await undici.request(url, { + dispatcher: this.getAgentByUrl(new URL(url), privateOptions.bypassProxy), + ...options, + headers: { + 'user-agent': this.userAgent ?? '', + ...(options.headers ?? {}), + }, + }).catch((err) => { + this.logger?.error(`fetch error to ${typeof url === 'string' ? url : url.href}`, err); + throw new StatusError('Resource Unreachable', 500, 'Resource Unreachable'); + }); + + if (res.statusCode >= 400) { + throw new StatusError(`${res.statusCode}`, res.statusCode, ''); + } + + return res; + } + @bindThis public async getJson(url: string, accept = 'application/json, */*', headers?: Record): Promise { - const res = await this.fetch( + const { body } = await this.request( url, { headers: Object.assign({ @@ -145,12 +170,12 @@ export class UndiciFetcher { }, ); - return await res.json() as T; + return await body.json() as T; } @bindThis public async getHtml(url: string, accept = 'text/html, */*', headers?: Record): Promise { - const res = await this.fetch( + const { body } = await this.request( url, { headers: Object.assign({ @@ -159,7 +184,7 @@ export class UndiciFetcher { }, ); - return await res.text(); + return await body.text(); } } @@ -167,6 +192,7 @@ export class UndiciFetcher { export class HttpRequestService { public defaultFetcher: UndiciFetcher; public fetch: UndiciFetcher['fetch']; + public request: UndiciFetcher['request']; public getHtml: UndiciFetcher['getHtml']; public defaultJsonFetcher: UndiciFetcher; public getJson: UndiciFetcher['getJson']; @@ -221,11 +247,12 @@ export class HttpRequestService { }, }; - this.maxSockets = Math.max(64, this.config.deliverJobConcurrency ?? 128); + this.maxSockets = Math.max(64, ((this.config.deliverJobConcurrency ?? 128) / (this.config.clusterLimit ?? 1))); this.defaultFetcher = this.createFetcher({}, {}, this.logger); this.fetch = this.defaultFetcher.fetch; + this.request = this.defaultFetcher.request; this.getHtml = this.defaultFetcher.getHtml; this.defaultJsonFetcher = this.createFetcher({ diff --git a/packages/backend/src/core/activitypub/ApRequestService.ts b/packages/backend/src/core/activitypub/ApRequestService.ts index fd7319702e..db87475c4c 100644 --- a/packages/backend/src/core/activitypub/ApRequestService.ts +++ b/packages/backend/src/core/activitypub/ApRequestService.ts @@ -9,10 +9,12 @@ import { HttpRequestService, UndiciFetcher } from '@/core/HttpRequestService.js' import { LoggerService } from '@/core/LoggerService.js'; import { bindThis } from '@/decorators.js'; import type Logger from '@/logger.js'; +import type { Dispatcher } from 'undici'; +import { DevNull } from '@/misc/dev-null.js'; type Request = { url: string; - method: string; + method: Dispatcher.HttpMethod; headers: Record; }; @@ -163,7 +165,7 @@ export class ApRequestService { }, }); - await this.undiciFetcher.fetch( + const response = await this.undiciFetcher.request( url, { method: req.request.method, @@ -171,6 +173,7 @@ export class ApRequestService { body, }, ); + response.body.pipe(new DevNull()); } /** diff --git a/packages/backend/src/misc/dev-null.ts b/packages/backend/src/misc/dev-null.ts new file mode 100644 index 0000000000..38b9d82669 --- /dev/null +++ b/packages/backend/src/misc/dev-null.ts @@ -0,0 +1,11 @@ +import { Writable, WritableOptions } from "node:stream"; + +export class DevNull extends Writable implements NodeJS.WritableStream { + constructor(opts?: WritableOptions) { + super(opts); + } + + _write (chunk: any, encoding: BufferEncoding, cb: (err?: Error | null) => void) { + setImmediate(cb); + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cdbbd3b825..3fdaf1449a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3801,7 +3801,7 @@ packages: /axios/0.24.0: resolution: {integrity: sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==} dependencies: - follow-redirects: 1.15.2 + follow-redirects: 1.15.2_debug@4.3.4 transitivePeerDependencies: - debug dev: false @@ -6973,16 +6973,6 @@ packages: readable-stream: 2.3.7 dev: false - /follow-redirects/1.15.2: - resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - dev: false - /follow-redirects/1.15.2_debug@4.3.4: resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} engines: {node: '>=4.0'} @@ -6993,7 +6983,6 @@ packages: optional: true dependencies: debug: 4.3.4 - dev: true /for-each/0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} From 8d3283e2a5dc49b9e9daa926c798efcb68bcec5e Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 24 Jan 2023 17:25:52 +0900 Subject: [PATCH 06/20] tweak ti style --- packages/frontend/src/style.scss | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss index 5d539a0f03..aa4efe3052 100644 --- a/packages/frontend/src/style.scss +++ b/packages/frontend/src/style.scss @@ -127,11 +127,13 @@ hr { } .ti { - vertical-align: -70%; - line-height: 0.5em; + vertical-align: -40%; + line-height: 1em; &:before { - font-size: 150%; + display: inline-block; + font-size: 165%; + width: 0.74em; } } From 9ca1197759b25b6244abd8dc14d19dcac3c23c8f Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 24 Jan 2023 17:26:49 +0900 Subject: [PATCH 07/20] :art: --- packages/frontend/src/components/MkNotification.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue index d8087eb23b..a8b8fec346 100644 --- a/packages/frontend/src/components/MkNotification.vue +++ b/packages/frontend/src/components/MkNotification.vue @@ -249,7 +249,7 @@ useTooltip(reactionRef, (showing) => { .t_achievementEarned { padding: 3px; - background: #88a6b7; + background: #cb9a11; pointer-events: none; } From 2c379732d2bd7ec655bd01d361ad0b955760c5d1 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 24 Jan 2023 17:28:38 +0900 Subject: [PATCH 08/20] New Crowdin updates (#9696) * New translations ja-JP.yml (Chinese Simplified) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (English) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (German) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (German) * New translations ja-JP.yml (Korean) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (English) * New translations ja-JP.yml (Korean) * New translations ja-JP.yml (Korean) * New translations ja-JP.yml (English) * New translations ja-JP.yml (Thai) * New translations ja-JP.yml (Italian) * New translations ja-JP.yml (Thai) * New translations ja-JP.yml (Italian) * New translations ja-JP.yml (Russian) * New translations ja-JP.yml (Korean) * New translations ja-JP.yml (Korean) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (Chinese Traditional) * New translations ja-JP.yml (Italian) * New translations ja-JP.yml (Chinese Traditional) --- locales/de-DE.yml | 10 +++++++-- locales/en-US.yml | 8 +++++++- locales/it-IT.yml | 26 +++++++++++++++--------- locales/ko-KR.yml | 52 ++++++++++++++++++++++++++--------------------- locales/ru-RU.yml | 2 +- locales/th-TH.yml | 37 +++++++++++++++++++++++++++++++++ locales/uk-UA.yml | 46 +++++++++++++++++++++++++++++++++++++++++ locales/zh-CN.yml | 3 +++ locales/zh-TW.yml | 10 +++++++-- 9 files changed, 155 insertions(+), 39 deletions(-) diff --git a/locales/de-DE.yml b/locales/de-DE.yml index e81f7579c2..a3e8f221df 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -1104,9 +1104,12 @@ _achievements: title: "I Love Misskey" description: "Sende \"I ❤ #Misskey\"" flavor: "Danke, dass du Misskey verwendest! - vom Entwicklerteam" + _foundTreasure: + title: "Schatzsuche" + description: "Du hast einen verborgenen Schatz gefunden" _client30min: - title: "Kleine Pause" - description: "Seit dem Öffnen deines Clients sind 30 Minuten vergangen" + title: "Kurze Pause" + description: "Habe Misskey für 30 Minuten geöffnet" _noteDeletedWithin1min: title: "Ups" description: "Lösche eine Notiz innerhalb von 1 Minute nachdem sie gesendet wurde" @@ -1124,6 +1127,9 @@ _achievements: _htl20npm: title: "Fließende Chronik" description: "Deine Startseitenchronik erreicht eine Geschwindigkeit von 20 npm (Notizen pro Minute)" + _viewInstanceChart: + title: "Analyst" + description: "Schau dir die Messwerte der Instanz an" _outputHelloWorldOnScratchpad: title: "Hallo Welt!" description: "Gib \"hello world\" in der Testumgebung aus" diff --git a/locales/en-US.yml b/locales/en-US.yml index 6a43d45697..4e2f18629a 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -945,7 +945,7 @@ _achievements: _notes1: title: "just setting up my msky" description: "Post your first note" - flavor: "Have a good Misskey life!" + flavor: "Have a good time with Misskey!" _notes10: title: "Some notes" description: "Post 10 notes" @@ -1104,6 +1104,9 @@ _achievements: title: "I Love Misskey" description: "Post \"I ❤ #Misskey\"" flavor: "Misskey's development team greatly appreciates your support!" + _foundTreasure: + title: "Treasure Hunt" + description: "You've found the hidden treasure" _client30min: title: "Short break" description: "Spend 30 minutes on Misskey" @@ -1124,6 +1127,9 @@ _achievements: _htl20npm: title: "Flowing Timeline" description: "Have the speed of your home timeline exceed 20 npm (notes per minute)" + _viewInstanceChart: + title: "Analyst" + description: "View your instance's charts" _outputHelloWorldOnScratchpad: title: "Hello, world!" description: "Output \"hello world\" in the Scratchpad" diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 1726a84ff8..66af4654cc 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -1059,8 +1059,8 @@ _achievements: description: "Aggiungi le orecchie da gatto al tuo profilo" flavor: "Ti chiamerò..." _following1: - title: "Hai seguito il tuo primo profilo" - description: "Il tuo primo profilo Follower" + title: "Il mio primo Follow" + description: "Hai seguito il tuo primo profilo" _following10: title: "Segui, segui!" description: "Hai seguito 10 profili" @@ -1074,17 +1074,17 @@ _achievements: title: "Sovraccarico di amici" description: "Hai seguito 300 profili" _followers1: - title: "Primo Follower" - description: "Hai ottenuto un Follower" + title: "Il primo profilo tuo Follower" + description: "Hai ottenuto il tuo primo Follower" _followers10: title: "Follow me!" - description: "Hai ottenuto 10 Follower" + description: "Hai ottenuto 10 profili Follower" _followers50: title: "Follower a frotte" description: "Hai ottenuto 50 Follower" _followers100: title: "Popolare" - description: "Hai ottenuto 100 Follower" + description: "Hai ottenuto 100 profili Follower" _followers300: title: "Mettetevi in fila" description: "Hai ottenuto 300 Follower" @@ -1093,7 +1093,7 @@ _achievements: description: "Hai ottenuto 500 Follower" _followers1000: title: "Influenzer" - description: "Hai superato i 1.000 Follower" + description: "Hai superato i 1.000 profili Follower" _collectAchievements30: title: "Collezionista di successi" description: "Hai raggiunto 30 obiettivi" @@ -1104,9 +1104,12 @@ _achievements: title: "I LOVE Misskey" description: "Pubblica «I ♥ #Misskey»" flavor: "Grazie per aver utilizzato Misskey! Dal team di sviluppo" + _foundTreasure: + title: "Caccia al tesoro" + description: "Hai trovato un tesoro nascosto" _client30min: title: "Piccola pausa" - description: "Hai passato più di 30 minuti di fila su Misskey" + description: "Hai passato più di 30 minuti su Misskey" _noteDeletedWithin1min: title: "Ooops!" description: "Hai eliminato una nota entro un minuto dalla sua pubblicazione" @@ -1124,6 +1127,9 @@ _achievements: _htl20npm: title: "Timeline scorrevole" description: "La tua Timeline personale ha superato la velocità di 20 Note orarie (Note al minuto)" + _viewInstanceChart: + title: "Analista" + description: "Visualizza i grafici dell'istanza" _outputHelloWorldOnScratchpad: title: "Hello, world!" description: "Hai scritto «Hello world» nel blocco appunti" @@ -1501,8 +1507,8 @@ _sfx: channel: "Notifiche di canale" _ago: future: "Futuro" - justNow: "Ora" - secondsAgo: "{n}s fa" + justNow: "Adesso" + secondsAgo: "{n} sec fa" minutesAgo: "{n} min fa" hoursAgo: "{n} ore fa" daysAgo: "{n} gg fa" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 97708a86d5..265f14ec59 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -938,13 +938,13 @@ cannotPerformTemporary: "일시적으로 사용할 수 없음" cannotPerformTemporaryDescription: "조작 횟수 제한을 초과하여 일시적으로 사용이 불가합니다. 잠시 후 다시 시도해 주세요." preset: "프리셋" selectFromPresets: "프리셋에서 선택" -achievements: "도전과제" +achievements: "도전 과제" _achievements: earnedAt: "달성 일시" _types: _notes1: - title: "미스키 설정하고 있었는데요" - description: "첫 노트를 포스트했습니다" + title: "미스키 시작했는데요" + description: "첫 노트를 작성했습니다" flavor: "Misskey에 오신 것을 환영합니다!" _notes10: title: "노트 조금" @@ -962,7 +962,7 @@ _achievements: title: "노트가 어디서 솟아?" description: "5,000개의 노트를 작성했습니다" _notes10000: - title: "슈퍼-노트" + title: "슈퍼 노트" description: "10,000개의 노트를 작성했습니다" _notes20000: title: "노트 더 없어?" @@ -989,7 +989,7 @@ _achievements: title: "노트 우주" description: "90,000개의 노트를 작성했습니다" _notes100000: - title: "네 모든 노트는 내 거야" + title: "ALL YOUR NOTE ARE BELONG TO US" description: "100,000개의 노트를 작성했습니다" flavor: "이만큼 쓸 일도 없겠지만... 다른 할 일이 있진 않으신가요?" _login3: @@ -1012,7 +1012,7 @@ _achievements: _login100: title: "미스키스트 III" description: "총 100일간 로그인했습니다" - flavor: "그 유저, 미스키스트를 위하여" + flavor: "그 유저, 미스키스트이다" _login200: title: "단골 I" description: "총 200일간 로그인했습니다" @@ -1025,7 +1025,7 @@ _achievements: _login500: title: "베테랑 I" description: "총 500일간 로그인했습니다" - flavor: "여러분, 저 이 노트들 좋아해요" + flavor: "제군, 나는 노트가 좋다" _login600: title: "베테랑 II" description: "총 600일간 로그인했습니다" @@ -1041,7 +1041,7 @@ _achievements: _login1000: title: "노트 마스터 III" description: "총 1,000일간 로그인했습니다" - flavor: "미스키를 사용해 주셔서 감사합니다!" + flavor: "Misskey를 사용해 주셔서 감사합니다!" _noteClipped1: title: "클립할 수밖에 없었어" description: "처음으로 노트를 클립했습니다" @@ -1049,7 +1049,7 @@ _achievements: title: "별을 바라보는 자" description: "처음으로 노트를 즐겨찾기했습니다" _myNoteFavorited1: - title: "I wanna Star" + title: "별을 원하는 자" description: "다른 사람이 당신의 노트를 즐겨찾기했습니다" _profileFilled: title: "준비 완료" @@ -1077,7 +1077,7 @@ _achievements: title: "첫 팔로워" description: "사용자가 처음으로 팔로잉했습니다" _followers10: - title: "날 따라와!" + title: "팔로우 미!" description: "10명의 사용자가 팔로우했습니다" _followers50: title: "이곳저곳" @@ -1095,15 +1095,18 @@ _achievements: title: "유명인사" description: "1,000명의 사용자가 팔로우했습니다" _collectAchievements30: - title: "도전과제 콜렉터" + title: "도전 과제 콜렉터" description: "30개의 도전과제를 획득했습니다" _viewAchievements3min: title: "저 도전과제 좋아해요" - description: "도전과제 목록을 3분 이상 보세요" + description: "도전 과제 목록을 3분 이상 쳐다봤습니다" _iLoveMisskey: title: "I Love Misskey" description: "\"I ❤ #Misskey\"를 포스트했습니다" flavor: "Misskey를 이용해주셔서 감사합니다! - 개발팀 일동" + _foundTreasure: + title: "보물찾기" + description: "숨겨진 보물을 발견했습니다" _client30min: title: "잠깐 쉬어" description: "클라이언트를 시작하고 30분이 경과하였습니다" @@ -1116,7 +1119,7 @@ _achievements: flavor: "잠 좀 자세요. 걱정돼요." _postedAt0min0sec: title: "정각" - description: "1초도 어긋나지 않은 정각에 노트를 포스트했습니다" + description: "0분 0초 정각에 노트를 작성했습니다" flavor: "째깍 째깍 째깍 땡!" _selfQuote: title: "혼잣말" @@ -1124,21 +1127,24 @@ _achievements: _htl20npm: title: "타임라인 폭주 중" description: "1분 사이에 홈 타임라인에 노트가 20개 넘게 생성되었습니다" + _viewInstanceChart: + title: "애널리스트" + description: "인스턴스의 차트를 열었습니다" _outputHelloWorldOnScratchpad: title: "Hello, world!" - description: "스크래치패드에서 hello world를 출력하세요" + description: "스크래치패드에서 hello world를 출력했습니다" _open3windows: title: "멀티 윈도우" - description: "3개 이상의 창을 여세요" + description: "3개 이상의 창을 열었습니다" _driveFolderCircularReference: title: "순환 참조" description: "드라이브 폴더를 자신을 가리키도록 만드려 시도했습니다" _reactWithoutRead: title: "읽고 답하긴 하시는 건가요?" - description: "100자가 넘는 포스트에 3초 안에 포스트했습니다" + description: "100자가 넘는 노트가 작성되고 3초 안에 반응했습니다" _clickedClickHere: title: "여길 눌러보세요" - description: "이 곳을 눌러봤습니다" + description: "여길을 눌러봤습니다" _justPlainLucky: title: "그냥 운이 좋았어" description: "매 10초마다 0.01%의 확률로 달성됩니다" @@ -1146,25 +1152,25 @@ _achievements: title: "신 콤플렉스" description: "이름을 syuilo로 설정했습니다" _passedSinceAccountCreated1: - title: "1년" + title: "1주년" description: "계정을 생성하고 1년이 지났습니다" _passedSinceAccountCreated2: - title: "2년" + title: "2주년" description: "계정을 생성하고 2년이 지났습니다" _passedSinceAccountCreated3: - title: "3년" + title: "3주년" description: "계정을 생성하고 3년이 지났습니다" _loggedInOnBirthday: title: "생일 축하합니다!" - description: "설정한 생일에 로그인했습니다" + description: "생일에 로그인했습니다" _loggedInOnNewYearsDay: title: "새해 복 많이 받으세요" description: "새해 첫 날에 로그인했습니다" flavor: "올해에도 저희 인스턴스에 관심을 가져 주셔서 감사합니다" _cookieClicked: - title: "쿠키 클리커 게임" + title: "쿠키를 클릭하는 게임" description: "쿠키를 클릭했습니다" - flavor: "뭔가 문제가 있나요?" + flavor: "소프트웨어 착각하지 않으셨나요?" _brainDiver: title: "Brain Diver" description: "Brain Diver로의 링크를 첨부했습니다" diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index 5419413984..1c01384662 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -1004,7 +1004,7 @@ _achievements: _login100: title: "Мискиец Ⅲ" description: "100 дней на сайте" - flavor: "Жестокий Misskist " + flavor: "Жестокий мискиец" _login200: title: "Завсегдатай Ⅰ" description: "200 дней на сайте" diff --git a/locales/th-TH.yml b/locales/th-TH.yml index 08737fb1b7..47c9a3a414 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -942,14 +942,51 @@ achievements: "ความสำเร็จ" _achievements: earnedAt: "ได้รับเมื่อ" _types: + _notes1: + title: "เพียงแค่ตั้งค่า msky ของฉัน" _followers100: title: "บุคคลที่เป็นที่นิยม" _followers500: title: "เสาสัญญาณ" + _followers1000: + title: "ผู้ทรงอิทธิพล" _iLoveMisskey: title: "ฉันรัก Misskey" + description: "โพสต์ \"I ❤ #Misskey\"" + _foundTreasure: + title: "ล่าสมบัติ" + description: "คุณพบสมบัติที่ซ่อนอยู่" + _client30min: + title: "พักผ่อนสักหน่อย" + _noteDeletedWithin1min: + title: "ไม่เป็นไร" + _postedAtLateNight: + title: "กลางคืน" + _viewInstanceChart: + title: "วิเคราะห์" + description: "ดูแผนภูมิอินสแตนซ์ของคุณ" _driveFolderCircularReference: title: "อ้างอิงวงจร" + _clickedClickHere: + title: "คลิ๊กที่นี่" + description: "คุณได้คลิกที่นี่" + _passedSinceAccountCreated1: + title: "ครบรอบหนึ่งปี" + _passedSinceAccountCreated2: + title: "ครบรอบสองปี" + _passedSinceAccountCreated3: + title: "ครบรอบสามปี" + _loggedInOnBirthday: + title: "สุขสันต์วันเกิด" + description: "เข้าสู่ระบบในวันเกิดของคุณ" + _loggedInOnNewYearsDay: + title: "สวัสดีปีใหม่!" + description: "เข้าสู่ระบบในวันแรกของปี" + _cookieClicked: + description: "คลิกคุกกี้" + _brainDiver: + title: "Brain Diver" + flavor: "Misskey-Misskey La-Tu-Ma" _role: new: "บทบาทใหม่" edit: "แก้ไขบทบาท" diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index ee978b58d6..f000337f3b 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -910,34 +910,80 @@ _achievements: title: "Декілька нотаток" description: "10 нотаток відправлено" _notes100: + title: "Купа нотаток" description: "100 нотаток відправлено" _notes500: + title: "Все в нотатках" description: "500 нотаток відправлено" _notes1000: + title: "Гора нотаток" description: "1 000 нотаток відправлено" _notes5000: + title: "Переповнюючі нотатки" description: "5 000 нотаток відправлено" _notes10000: + title: "Супернотатка" description: "10 000 нотаток відправлено" _notes20000: + title: "Треба Більше Нотаток" description: "20 000 нотаток відправлено" _notes30000: + title: "Нотатки нотатки нотатки" description: "30 000 нотаток відправлено" _notes40000: + title: "Фабрика нотаток" description: "40 000 нотаток відправлено" _notes50000: + title: "Планета нотаток" description: "50 000 нотаток відправлено" _notes60000: + title: "Нотатковий квазар" description: "60 000 нотаток відправлено" _notes70000: + title: "Чорна нотаткова діра" description: "70 000 нотаток відправлено" _notes80000: + title: "Галактика нотаток" description: "80 000 нотаток відправлено" _notes90000: + title: "Нотатковерс" description: "90 000 нотаток відправлено" _notes100000: title: "ALL YOUR NOTE ARE BELONG TO US" description: "100 000 нотаток відправлено" + flavor: "Так багато потрібно сказати?" + _login3: + title: "Новачок I" + _login7: + title: "Новачок II" + _login15: + title: "Новачок III" + _login30: + title: "Міскієць I" + _login60: + title: "Міскієць II" + _login100: + title: "Міскієць III" + _login200: + title: "Завсідник I" + _login300: + title: "Завсідник II" + _login400: + title: "Завсідник III" + _login500: + title: "Ветеран I" + _login600: + title: "Ветеран II" + _login700: + title: "Ветеран III" + _login1000: + flavor: "Дякуємо, що користуєтеся Misskey!" + _passedSinceAccountCreated3: + description: "Минуло 3 роки з моменту створення акаунта" + _loggedInOnBirthday: + title: "З Днем народження!" + _brainDiver: + flavor: "Misskey-Misskey La-Tu-Ma" _role: priority: "Пріоритет" _priority: diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 433af4c836..9d20b85448 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -1007,6 +1007,9 @@ _achievements: flavor: "感谢您使用Misskey!" _noteFavorited1: title: "观星者" + _profileFilled: + title: "整装待发" + description: "设置了个人资料" _markedAsCat: title: "我是猫" description: "将账户设定为一只猫" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index a8a06528d2..c40476c34a 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -950,13 +950,13 @@ _achievements: title: "若干貼文" description: "發表了10則貼文" _notes100: - title: "許多的貼文" + title: "許多貼文" description: "發表了100則貼文" _notes500: title: "滿滿的貼文" description: "發表了500則貼文" _notes1000: - title: "一堆貼文" + title: "堆積如山的貼文" description: "發表了1000則貼文" _notes5000: title: "滔滔不絕的貼文" @@ -1104,6 +1104,9 @@ _achievements: title: "I Love Misskey" description: "發布「I ❤ #Misskey」" flavor: "感謝您使用Misskey! by 開發團隊" + _foundTreasure: + title: "尋寶" + description: "發現了隱藏的寶藏" _client30min: title: "休息一下" description: "用戶端啟動已超過30分鐘" @@ -1124,6 +1127,9 @@ _achievements: _htl20npm: title: "流動的TL" description: "在首頁時間軸的流速超過20npm" + _viewInstanceChart: + title: "分析師" + description: "顯示了實例的圖表" _outputHelloWorldOnScratchpad: title: "Hello world!" description: "在暫存記憶體輸出了 hello world" From 117ac53505b264edbac787e165ed45ea1a7e3db0 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 24 Jan 2023 17:30:51 +0900 Subject: [PATCH 09/20] 13.2.1 --- CHANGELOG.md | 7 ++++++- package.json | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fd48fcbdb..5f2d8ad378 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,12 @@ You should also include the user name that made the change. --> -## 13.2.0 (2021/01/23) +## 13.2.1 (2023/01/24) +### Improvements +- デザインの調整 +- サーバーのパフォーマンスを改善 + +## 13.2.0 (2023/01/23) ### Improvements - onlyServer / onlyQueue オプションを復活 diff --git a/package.json b/package.json index 7b0d5093d1..32f1f83943 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.2.0", + "version": "13.2.1", "codename": "nasubi", "repository": { "type": "git", From 8cab16c824f27a1ebc6b67c8012504eb58e50e20 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 24 Jan 2023 17:51:09 +0900 Subject: [PATCH 10/20] fix(server): /api/signin always returns 429 when request header x-forwarded-for contains client port Fix #9408 --- packages/backend/src/misc/get-ip-hash.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/backend/src/misc/get-ip-hash.ts b/packages/backend/src/misc/get-ip-hash.ts index 379325bb13..70e61aef8c 100644 --- a/packages/backend/src/misc/get-ip-hash.ts +++ b/packages/backend/src/misc/get-ip-hash.ts @@ -1,9 +1,14 @@ import IPCIDR from 'ip-cidr'; export function getIpHash(ip: string) { - // because a single person may control many IPv6 addresses, - // only a /64 subnet prefix of any IP will be taken into account. - // (this means for IPv4 the entire address is used) - const prefix = IPCIDR.createAddress(ip).mask(64); - return 'ip-' + BigInt('0b' + prefix).toString(36); + try { + // because a single person may control many IPv6 addresses, + // only a /64 subnet prefix of any IP will be taken into account. + // (this means for IPv4 the entire address is used) + const prefix = IPCIDR.createAddress(ip).mask(64); + return 'ip-' + BigInt('0b' + prefix).toString(36); + } catch (e) { + const prefix = IPCIDR.createAddress(ip.replace(/:[0-9]+$/, '')).mask(64); + return 'ip-' + BigInt('0b' + prefix).toString(36); + } } From 520ed8cb4d04004717e25185a8805e05ece413d7 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 25 Jan 2023 11:18:16 +0900 Subject: [PATCH 11/20] refactor(server): fix type errors --- packages/backend/src/core/AntennaService.ts | 10 ++++++-- packages/backend/src/core/RoleService.ts | 26 +++++++++++++-------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/packages/backend/src/core/AntennaService.ts b/packages/backend/src/core/AntennaService.ts index be755f7dab..7db8c43ea5 100644 --- a/packages/backend/src/core/AntennaService.ts +++ b/packages/backend/src/core/AntennaService.ts @@ -77,10 +77,16 @@ export class AntennaService implements OnApplicationShutdown { const { type, body } = obj.message as StreamMessages['internal']['payload']; switch (type) { case 'antennaCreated': - this.antennas.push(body); + this.antennas.push({ + ...body, + createdAt: new Date(body.createdAt), + }); break; case 'antennaUpdated': - this.antennas[this.antennas.findIndex(a => a.id === body.id)] = body; + this.antennas[this.antennas.findIndex(a => a.id === body.id)] = { + ...body, + createdAt: new Date(body.createdAt), + }; break; case 'antennaDeleted': this.antennas = this.antennas.filter(a => a.id !== body.id); diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index c0f5eae3d7..f8f9231cdd 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -91,10 +91,12 @@ export class RoleService implements OnApplicationShutdown { case 'roleCreated': { const cached = this.rolesCache.get(null); if (cached) { - body.createdAt = new Date(body.createdAt); - body.updatedAt = new Date(body.updatedAt); - body.lastUsedAt = new Date(body.lastUsedAt); - cached.push(body); + cached.push({ + ...body, + createdAt: new Date(body.createdAt), + updatedAt: new Date(body.updatedAt), + lastUsedAt: new Date(body.lastUsedAt), + }); } break; } @@ -103,10 +105,12 @@ export class RoleService implements OnApplicationShutdown { if (cached) { const i = cached.findIndex(x => x.id === body.id); if (i > -1) { - body.createdAt = new Date(body.createdAt); - body.updatedAt = new Date(body.updatedAt); - body.lastUsedAt = new Date(body.lastUsedAt); - cached[i] = body; + cached[i] = { + ...body, + createdAt: new Date(body.createdAt), + updatedAt: new Date(body.updatedAt), + lastUsedAt: new Date(body.lastUsedAt), + }; } } break; @@ -121,8 +125,10 @@ export class RoleService implements OnApplicationShutdown { case 'userRoleAssigned': { const cached = this.roleAssignmentByUserIdCache.get(body.userId); if (cached) { - body.createdAt = new Date(body.createdAt); - cached.push(body); + cached.push({ + ...body, + createdAt: new Date(body.createdAt), + }); } break; } From 2a2e8d0cf6a83c4a10e3a62331d6fbd3adb416a6 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 25 Jan 2023 11:23:57 +0900 Subject: [PATCH 12/20] refactor(server): fix type errors --- .../backend/src/core/activitypub/ApRendererService.ts | 2 +- .../src/core/activitypub/models/ApPersonService.ts | 8 ++++---- packages/backend/src/server/api/stream/types.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 29f216aa1d..91a2767e69 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -21,11 +21,11 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import type { UserKeypair } from '@/models/entities/UserKeypair.js'; import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, EmojisRepository, PollsRepository } from '@/models/index.js'; +import { bindThis } from '@/decorators.js'; import { LdSignatureService } from './LdSignatureService.js'; import { ApMfmService } from './ApMfmService.js'; import type { IActivity, IObject } from './type.js'; import type { IIdentifier } from './models/identifier.js'; -import { bindThis } from '@/decorators.js'; @Injectable() export class ApRendererService { diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index e08f33c906..f86b5e6f96 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -566,22 +566,22 @@ export class ApPersonService implements OnModuleInit { this.logger.info(`Updating the featured: ${user.uri}`); - if (resolver == null) resolver = this.apResolverService.createResolver(); + const _resolver = resolver ?? this.apResolverService.createResolver(); // Resolve to (Ordered)Collection Object - const collection = await resolver.resolveCollection(user.featured); + const collection = await _resolver.resolveCollection(user.featured); if (!isCollectionOrOrderedCollection(collection)) throw new Error('Object is not Collection or OrderedCollection'); // Resolve to Object(may be Note) arrays const unresolvedItems = isCollection(collection) ? collection.items : collection.orderedItems; - const items = await Promise.all(toArray(unresolvedItems).map(x => resolver.resolve(x))); + const items = await Promise.all(toArray(unresolvedItems).map(x => _resolver.resolve(x))); // Resolve and regist Notes const limit = promiseLimit(2); const featuredNotes = await Promise.all(items .filter(item => getApType(item) === 'Note') // TODO: Noteでなくてもいいかも .slice(0, 5) - .map(item => limit(() => this.apNoteService.resolveNote(item, resolver)))); + .map(item => limit(() => this.apNoteService.resolveNote(item, _resolver)))); await this.db.transaction(async transactionalEntityManager => { await transactionalEntityManager.delete(UserNotePining, { userId: user.id }); diff --git a/packages/backend/src/server/api/stream/types.ts b/packages/backend/src/server/api/stream/types.ts index a442529bb3..ef65b27ddc 100644 --- a/packages/backend/src/server/api/stream/types.ts +++ b/packages/backend/src/server/api/stream/types.ts @@ -30,7 +30,7 @@ export interface InternalStreamTypes { remoteUserUpdated: Serialized<{ id: User['id']; }>; follow: Serialized<{ followerId: User['id']; followeeId: User['id']; }>; unfollow: Serialized<{ followerId: User['id']; followeeId: User['id']; }>; - policiesUpdated: Serialized; + policiesUpdated: Serialized; roleCreated: Serialized; roleDeleted: Serialized; roleUpdated: Serialized; From d4fb201d05fc4e0da85f21eece7cc6baf30b6d05 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 25 Jan 2023 12:00:04 +0900 Subject: [PATCH 13/20] =?UTF-8?q?fix(server):=20node-fetch=E3=81=8A?= =?UTF-8?q?=E3=82=88=E3=81=B3got=E3=82=92=E4=BD=BF=E3=81=86=E4=BB=A5?= =?UTF-8?q?=E5=89=8D=E3=81=AE=E5=AE=9F=E8=A3=85=E3=81=AB=E6=88=BB=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit see #9710 --- packages/backend/package.json | 3 +- packages/backend/src/core/CaptchaService.ts | 17 +- packages/backend/src/core/DownloadService.ts | 76 ++-- .../src/core/FetchInstanceMetadataService.ts | 5 +- .../backend/src/core/HttpRequestService.ts | 381 ++++-------------- packages/backend/src/core/S3Service.ts | 2 +- .../src/core/activitypub/ApRequestService.ts | 35 +- .../src/core/activitypub/ApResolverService.ts | 10 +- .../core/activitypub/LdSignatureService.ts | 19 +- .../WebhookDeliverProcessorService.ts | 39 +- .../src/server/api/endpoints/fetch-rss.ts | 17 +- .../server/api/endpoints/notes/translate.ts | 22 +- pnpm-lock.yaml | 4 +- 13 files changed, 203 insertions(+), 427 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index 6cac949ea7..586b95f2e5 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -63,7 +63,7 @@ "file-type": "18.2.0", "fluent-ffmpeg": "2.1.2", "form-data": "^4.0.0", - "got": "12.5.3", + "got": "^12.5.3", "hpagent": "1.2.0", "ioredis": "4.28.5", "ip-cidr": "3.0.11", @@ -119,7 +119,6 @@ "typeorm": "0.3.11", "typescript": "4.9.4", "ulid": "2.3.0", - "undici": "^5.16.0", "unzipper": "0.10.11", "uuid": "9.0.0", "vary": "1.1.2", diff --git a/packages/backend/src/core/CaptchaService.ts b/packages/backend/src/core/CaptchaService.ts index 1e98914052..c8428a26b0 100644 --- a/packages/backend/src/core/CaptchaService.ts +++ b/packages/backend/src/core/CaptchaService.ts @@ -21,18 +21,13 @@ export class CaptchaService { response, }); - const res = await this.httpRequestService.fetch( - url, - { - method: 'POST', - body: params, + const res = await this.httpRequestService.send(url, { + method: 'POST', + body: JSON.stringify(params), + headers: { + 'Content-Type': 'application/json', }, - { - noOkError: true, - } - ).catch(err => { - throw `${err.message ?? err}`; - }); + }, { throwErrorWhenResponseNotOk: false }); if (!res.ok) { throw `${res.status}`; diff --git a/packages/backend/src/core/DownloadService.ts b/packages/backend/src/core/DownloadService.ts index c5b2bcaef4..a971e06fd8 100644 --- a/packages/backend/src/core/DownloadService.ts +++ b/packages/backend/src/core/DownloadService.ts @@ -5,10 +5,10 @@ import { Inject, Injectable } from '@nestjs/common'; import IPCIDR from 'ip-cidr'; import PrivateIp from 'private-ip'; import chalk from 'chalk'; -import { buildConnector } from 'undici'; +import got, * as Got from 'got'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; -import { HttpRequestService, UndiciFetcher } from '@/core/HttpRequestService.js'; +import { HttpRequestService } from '@/core/HttpRequestService.js'; import { createTemp } from '@/misc/create-temp.js'; import { StatusError } from '@/misc/status-error.js'; import { LoggerService } from '@/core/LoggerService.js'; @@ -20,7 +20,6 @@ import { bindThis } from '@/decorators.js'; @Injectable() export class DownloadService { private logger: Logger; - private undiciFetcher: UndiciFetcher; constructor( @Inject(DI.config) @@ -30,21 +29,6 @@ export class DownloadService { private loggerService: LoggerService, ) { this.logger = this.loggerService.getLogger('download'); - - this.undiciFetcher = this.httpRequestService.createFetcher({ - connect: process.env.NODE_ENV === 'development' ? - this.httpRequestService.clientDefaults.connect - : - this.httpRequestService.getConnectorWithIpCheck( - buildConnector({ - ...this.httpRequestService.clientDefaults.connect, - }), - (ip) => !this.isPrivateIp(ip), - ), - bodyTimeout: 30 * 1000, - }, { - connect: this.httpRequestService.clientDefaults.connect, - }, this.logger); } @bindThis @@ -55,14 +39,60 @@ export class DownloadService { const operationTimeout = 60 * 1000; const maxSize = this.config.maxFileSize ?? 262144000; - const response = await this.undiciFetcher.fetch(url); + const req = got.stream(url, { + headers: { + 'User-Agent': this.config.userAgent, + }, + timeout: { + lookup: timeout, + connect: timeout, + secureConnect: timeout, + socket: timeout, // read timeout + response: timeout, + send: timeout, + request: operationTimeout, // whole operation timeout + }, + agent: { + http: this.httpRequestService.httpAgent, + https: this.httpRequestService.httpsAgent, + }, + http2: false, // default + retry: { + limit: 0, + }, + }).on('response', (res: Got.Response) => { + if ((process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test') && !this.config.proxy && res.ip) { + if (this.isPrivateIp(res.ip)) { + this.logger.warn(`Blocked address: ${res.ip}`); + req.destroy(); + } + } - if (response.body === null) { - throw new StatusError('No body', 400, 'No body'); + const contentLength = res.headers['content-length']; + if (contentLength != null) { + const size = Number(contentLength); + if (size > maxSize) { + this.logger.warn(`maxSize exceeded (${size} > ${maxSize}) on response`); + req.destroy(); + } + } + }).on('downloadProgress', (progress: Got.Progress) => { + if (progress.transferred > maxSize) { + this.logger.warn(`maxSize exceeded (${progress.transferred} > ${maxSize}) on downloadProgress`); + req.destroy(); + } + }); + + try { + await pipeline(req, fs.createWriteStream(path)); + } catch (e) { + if (e instanceof Got.HTTPError) { + throw new StatusError(`${e.response.statusCode} ${e.response.statusMessage}`, e.response.statusCode, e.response.statusMessage); + } else { + throw e; + } } - await pipeline(stream.Readable.fromWeb(response.body), fs.createWriteStream(path)); - this.logger.succ(`Download finished: ${chalk.cyan(url)}`); } diff --git a/packages/backend/src/core/FetchInstanceMetadataService.ts b/packages/backend/src/core/FetchInstanceMetadataService.ts index cb9d099a22..35f30deeb4 100644 --- a/packages/backend/src/core/FetchInstanceMetadataService.ts +++ b/packages/backend/src/core/FetchInstanceMetadataService.ts @@ -2,6 +2,7 @@ import { URL } from 'node:url'; import { Inject, Injectable } from '@nestjs/common'; import { JSDOM } from 'jsdom'; import tinycolor from 'tinycolor2'; +import fetch from 'node-fetch'; import type { Instance } from '@/models/entities/Instance.js'; import type { InstancesRepository } from '@/models/index.js'; import { AppLockService } from '@/core/AppLockService.js'; @@ -190,7 +191,9 @@ export class FetchInstanceMetadataService { const faviconUrl = url + '/favicon.ico'; - const favicon = await this.httpRequestService.fetch(faviconUrl, {}, { noOkError: true }); + const favicon = await this.httpRequestService.send(faviconUrl, { + method: 'HEAD', + }, { throwErrorWhenResponseNotOk: false }); if (favicon.ok) { return faviconUrl; diff --git a/packages/backend/src/core/HttpRequestService.ts b/packages/backend/src/core/HttpRequestService.ts index cd859d0023..baf74acfa6 100644 --- a/packages/backend/src/core/HttpRequestService.ts +++ b/packages/backend/src/core/HttpRequestService.ts @@ -1,284 +1,67 @@ import * as http from 'node:http'; import * as https from 'node:https'; -import { LookupFunction } from 'node:net'; import CacheableLookup from 'cacheable-lookup'; +import fetch from 'node-fetch'; import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent'; import { Inject, Injectable } from '@nestjs/common'; -import * as undici from 'undici'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import { StatusError } from '@/misc/status-error.js'; import { bindThis } from '@/decorators.js'; -import { LoggerService } from '@/core/LoggerService.js'; -import type Logger from '@/logger.js'; - -// true to allow, false to deny -export type IpChecker = (ip: string) => boolean; - -/* - * Child class to create and save Agent for fetch. - * You should construct this when you want - * to change timeout, size limit, socket connect function, etc. - */ -export class UndiciFetcher { - /** - * Get http non-proxy agent (undici) - */ - public nonProxiedAgent: undici.Agent; - - /** - * Get http proxy or non-proxy agent (undici) - */ - public agent: undici.ProxyAgent | undici.Agent; - - private proxyBypassHosts: string[]; - private userAgent: string | undefined; - - private logger: Logger | undefined; - - constructor( - args: { - agentOptions: undici.Agent.Options; - proxy?: { - uri: string; - options?: undici.Agent.Options; // Override of agentOptions - }, - proxyBypassHosts?: string[]; - userAgent?: string; - }, - logger?: Logger, - ) { - this.logger = logger; - this.logger?.debug('UndiciFetcher constructor', args); - - this.proxyBypassHosts = args.proxyBypassHosts ?? []; - this.userAgent = args.userAgent; - - this.nonProxiedAgent = new undici.Agent({ - ...args.agentOptions, - connect: (process.env.NODE_ENV !== 'production' && typeof args.agentOptions.connect !== 'function') - ? (options, cb) => { - // Custom connector for debug - undici.buildConnector(args.agentOptions.connect as undici.buildConnector.BuildOptions)(options, (err, socket) => { - this.logger?.debug('Socket connector called', socket); - if (err) { - this.logger?.debug('Socket error', err); - cb(new Error(`Error while socket connecting\n${err}`), null); - return; - } - this.logger?.debug(`Socket connected: port ${socket.localPort} => remote ${socket.remoteAddress}`); - cb(null, socket); - }); - } : args.agentOptions.connect, - }); - - this.agent = args.proxy - ? new undici.ProxyAgent({ - ...args.agentOptions, - ...args.proxy.options, - - uri: args.proxy.uri, - - connect: (process.env.NODE_ENV !== 'production' && typeof (args.proxy.options?.connect ?? args.agentOptions.connect) !== 'function') - ? (options, cb) => { - // Custom connector for debug - undici.buildConnector((args.proxy?.options?.connect ?? args.agentOptions.connect) as undici.buildConnector.BuildOptions)(options, (err, socket) => { - this.logger?.debug('Socket connector called (secure)', socket); - if (err) { - this.logger?.debug('Socket error', err); - cb(new Error(`Error while socket connecting\n${err}`), null); - return; - } - this.logger?.debug(`Socket connected (secure): port ${socket.localPort} => remote ${socket.remoteAddress}`); - cb(null, socket); - }); - } : (args.proxy.options?.connect ?? args.agentOptions.connect), - }) - : this.nonProxiedAgent; - } - - /** - * Get agent by URL - * @param url URL - * @param bypassProxy Allways bypass proxy - */ - @bindThis - public getAgentByUrl(url: URL, bypassProxy = false): undici.Agent | undici.ProxyAgent { - if (bypassProxy || this.proxyBypassHosts.includes(url.hostname)) { - return this.nonProxiedAgent; - } else { - return this.agent; - } - } - - @bindThis - public async fetch( - url: string | URL, - options: undici.RequestInit = {}, - privateOptions: { noOkError?: boolean; bypassProxy?: boolean; } = { noOkError: false, bypassProxy: false }, - ): Promise { - const res = await undici.fetch(url, { - dispatcher: this.getAgentByUrl(new URL(url), privateOptions.bypassProxy), - ...options, - headers: { - 'User-Agent': this.userAgent ?? '', - ...(options.headers ?? {}), - }, - }).catch((err) => { - this.logger?.error(`fetch error to ${typeof url === 'string' ? url : url.href}`, err); - throw new StatusError('Resource Unreachable', 500, 'Resource Unreachable'); - }); - if (!res.ok && !privateOptions.noOkError) { - throw new StatusError(`${res.status} ${res.statusText}`, res.status, res.statusText); - } - return res; - } - - @bindThis - public async request( - url: string | URL, - options: { dispatcher?: undici.Dispatcher } & Omit & Partial> = {}, - privateOptions: { noOkError?: boolean; bypassProxy?: boolean; } = { noOkError: false, bypassProxy: false }, - ): Promise { - const res = await undici.request(url, { - dispatcher: this.getAgentByUrl(new URL(url), privateOptions.bypassProxy), - ...options, - headers: { - 'user-agent': this.userAgent ?? '', - ...(options.headers ?? {}), - }, - }).catch((err) => { - this.logger?.error(`fetch error to ${typeof url === 'string' ? url : url.href}`, err); - throw new StatusError('Resource Unreachable', 500, 'Resource Unreachable'); - }); - - if (res.statusCode >= 400) { - throw new StatusError(`${res.statusCode}`, res.statusCode, ''); - } - - return res; - } - - @bindThis - public async getJson(url: string, accept = 'application/json, */*', headers?: Record): Promise { - const { body } = await this.request( - url, - { - headers: Object.assign({ - Accept: accept, - }, headers ?? {}), - }, - ); - - return await body.json() as T; - } - - @bindThis - public async getHtml(url: string, accept = 'text/html, */*', headers?: Record): Promise { - const { body } = await this.request( - url, - { - headers: Object.assign({ - Accept: accept, - }, headers ?? {}), - }, - ); - - return await body.text(); - } -} +import type { Response } from 'node-fetch'; +import type { URL } from 'node:url'; @Injectable() export class HttpRequestService { - public defaultFetcher: UndiciFetcher; - public fetch: UndiciFetcher['fetch']; - public request: UndiciFetcher['request']; - public getHtml: UndiciFetcher['getHtml']; - public defaultJsonFetcher: UndiciFetcher; - public getJson: UndiciFetcher['getJson']; - - //#region for old http/https, only used in S3Service - // http non-proxy agent + /** + * Get http non-proxy agent + */ private http: http.Agent; - // https non-proxy agent + /** + * Get https non-proxy agent + */ private https: https.Agent; - // http proxy or non-proxy agent + /** + * Get http proxy or non-proxy agent + */ public httpAgent: http.Agent; - // https proxy or non-proxy agent + /** + * Get https proxy or non-proxy agent + */ public httpsAgent: https.Agent; - //#endregion - - public readonly dnsCache: CacheableLookup; - public readonly clientDefaults: undici.Agent.Options; - private maxSockets: number; - - private logger: Logger; constructor( @Inject(DI.config) private config: Config, - private loggerService: LoggerService, ) { - this.logger = this.loggerService.getLogger('http-request'); - - this.dnsCache = new CacheableLookup({ + const cache = new CacheableLookup({ maxTtl: 3600, // 1hours errorTtl: 30, // 30secs lookup: false, // nativeのdns.lookupにfallbackしない }); - - this.clientDefaults = { - keepAliveTimeout: 30 * 1000, - keepAliveMaxTimeout: 10 * 60 * 1000, - keepAliveTimeoutThreshold: 1 * 1000, - strictContentLength: true, - headersTimeout: 10 * 1000, - bodyTimeout: 10 * 1000, - maxHeaderSize: 16364, // default - maxResponseSize: 10 * 1024 * 1024, - maxRedirections: 3, - connect: { - timeout: 10 * 1000, // コネクションが確立するまでのタイムアウト - maxCachedSessions: 300, // TLSセッションのキャッシュ数 https://github.com/nodejs/undici/blob/v5.14.0/lib/core/connect.js#L80 - lookup: this.dnsCache.lookup as LookupFunction, // https://github.com/nodejs/undici/blob/v5.14.0/lib/core/connect.js#L98 - }, - }; - - this.maxSockets = Math.max(64, ((this.config.deliverJobConcurrency ?? 128) / (this.config.clusterLimit ?? 1))); - - this.defaultFetcher = this.createFetcher({}, {}, this.logger); - - this.fetch = this.defaultFetcher.fetch; - this.request = this.defaultFetcher.request; - this.getHtml = this.defaultFetcher.getHtml; - - this.defaultJsonFetcher = this.createFetcher({ - maxResponseSize: 1024 * 256, - }, {}, this.logger); - - this.getJson = this.defaultJsonFetcher.getJson; - - //#region for old http/https, only used in S3Service + this.http = new http.Agent({ keepAlive: true, keepAliveMsecs: 30 * 1000, - lookup: this.dnsCache.lookup, + lookup: cache.lookup, } as http.AgentOptions); this.https = new https.Agent({ keepAlive: true, keepAliveMsecs: 30 * 1000, - lookup: this.dnsCache.lookup, + lookup: cache.lookup, } as https.AgentOptions); - + + const maxSockets = Math.max(256, config.deliverJobConcurrency ?? 128); + this.httpAgent = config.proxy ? new HttpProxyAgent({ keepAlive: true, keepAliveMsecs: 30 * 1000, - maxSockets: this.maxSockets, + maxSockets, maxFreeSockets: 256, scheduling: 'lifo', proxy: config.proxy, @@ -289,47 +72,21 @@ export class HttpRequestService { ? new HttpsProxyAgent({ keepAlive: true, keepAliveMsecs: 30 * 1000, - maxSockets: this.maxSockets, + maxSockets, maxFreeSockets: 256, scheduling: 'lifo', proxy: config.proxy, }) : this.https; - //#endregion - } - - @bindThis - private getStandardUndiciFetcherOption(opts: undici.Agent.Options = {}, proxyOpts: undici.Agent.Options = {}) { - return { - agentOptions: { - ...this.clientDefaults, - ...opts, - }, - ...(this.config.proxy ? { - proxy: { - uri: this.config.proxy, - options: { - connections: this.maxSockets, - ...proxyOpts, - }, - }, - } : {}), - userAgent: this.config.userAgent, - }; - } - - @bindThis - public createFetcher(opts: undici.Agent.Options = {}, proxyOpts: undici.Agent.Options = {}, logger: Logger) { - return new UndiciFetcher(this.getStandardUndiciFetcherOption(opts, proxyOpts), logger); } /** - * Get http agent by URL + * Get agent by URL * @param url URL * @param bypassProxy Allways bypass proxy */ @bindThis - public getHttpAgentByUrl(url: URL, bypassProxy = false): http.Agent | https.Agent { + public getAgentByUrl(url: URL, bypassProxy = false): http.Agent | https.Agent { if (bypassProxy || (this.config.proxyBypassHosts || []).includes(url.hostname)) { return url.protocol === 'http:' ? this.http : this.https; } else { @@ -337,37 +94,67 @@ export class HttpRequestService { } } - /** - * check ip - */ @bindThis - public getConnectorWithIpCheck(connector: undici.buildConnector.connector, checkIp: IpChecker): undici.buildConnector.connectorAsync { - return (options, cb) => { - connector(options, (err, socket) => { - this.logger.debug('Socket connector (with ip checker) called', socket); - if (err) { - this.logger.error('Socket error', err); - cb(new Error(`Error while socket connecting\n${err}`), null); - return; - } + public async getJson(url: string, accept = 'application/json, */*', headers?: Record): Promise { + const res = await this.send(url, { + method: 'GET', + headers: Object.assign({ + 'User-Agent': this.config.userAgent, + Accept: accept, + }, headers ?? {}), + timeout: 5000, + size: 1024 * 256, + }); - if (socket.remoteAddress == undefined) { - this.logger.error('Socket error: remoteAddress is undefined'); - cb(new Error('remoteAddress is undefined (maybe socket destroyed)'), null); - return; - } + return await res.json(); + } - // allow - if (checkIp(socket.remoteAddress)) { - this.logger.debug(`Socket connected (ip ok): ${socket.localPort} => ${socket.remoteAddress}`); - cb(null, socket); - return; - } + @bindThis + public async getHtml(url: string, accept = 'text/html, */*', headers?: Record): Promise { + const res = await this.send(url, { + method: 'GET', + headers: Object.assign({ + 'User-Agent': this.config.userAgent, + Accept: accept, + }, headers ?? {}), + timeout: 5000, + }); - this.logger.error('IP is not allowed', socket); - cb(new StatusError('IP is not allowed', 403, 'IP is not allowed'), null); - socket.destroy(); - }); - }; + return await res.text(); + } + + @bindThis + public async send(url: string, args: { + method?: string, + body?: string, + headers?: Record, + timeout?: number, + size?: number, + } = {}, extra: { + throwErrorWhenResponseNotOk: boolean; + } = { + throwErrorWhenResponseNotOk: true, + }): Promise { + const timeout = args.timeout ?? 5000; + + const controller = new AbortController(); + setTimeout(() => { + controller.abort(); + }, timeout); + + const res = await fetch(url, { + method: args.method ?? 'GET', + headers: args.headers, + body: args.body, + size: args.size ?? 10 * 1024 * 1024, + agent: (url) => this.getAgentByUrl(url), + signal: controller.signal, + }); + + if (!res.ok && extra.throwErrorWhenResponseNotOk) { + throw new StatusError(`${res.status} ${res.statusText}`, res.status, res.statusText); + } + + return res; } } diff --git a/packages/backend/src/core/S3Service.ts b/packages/backend/src/core/S3Service.ts index 930188ce6e..0ce69aaa74 100644 --- a/packages/backend/src/core/S3Service.ts +++ b/packages/backend/src/core/S3Service.ts @@ -33,7 +33,7 @@ export class S3Service { ? false : meta.objectStorageS3ForcePathStyle, httpOptions: { - agent: this.httpRequestService.getHttpAgentByUrl(new URL(u), !meta.objectStorageUseProxy), + agent: this.httpRequestService.getAgentByUrl(new URL(u), !meta.objectStorageUseProxy), }, }); } diff --git a/packages/backend/src/core/activitypub/ApRequestService.ts b/packages/backend/src/core/activitypub/ApRequestService.ts index db87475c4c..b949f34841 100644 --- a/packages/backend/src/core/activitypub/ApRequestService.ts +++ b/packages/backend/src/core/activitypub/ApRequestService.ts @@ -5,16 +5,14 @@ import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import type { User } from '@/models/entities/User.js'; import { UserKeypairStoreService } from '@/core/UserKeypairStoreService.js'; -import { HttpRequestService, UndiciFetcher } from '@/core/HttpRequestService.js'; +import { HttpRequestService } from '@/core/HttpRequestService.js'; import { LoggerService } from '@/core/LoggerService.js'; import { bindThis } from '@/decorators.js'; import type Logger from '@/logger.js'; -import type { Dispatcher } from 'undici'; -import { DevNull } from '@/misc/dev-null.js'; type Request = { url: string; - method: Dispatcher.HttpMethod; + method: string; headers: Record; }; @@ -32,7 +30,6 @@ type PrivateKey = { @Injectable() export class ApRequestService { - private undiciFetcher: UndiciFetcher; private logger: Logger; constructor( @@ -44,9 +41,6 @@ export class ApRequestService { private loggerService: LoggerService, ) { this.logger = this.loggerService.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる - this.undiciFetcher = this.httpRequestService.createFetcher({ - maxRedirections: 0, - }, {}, this.logger); } @bindThis @@ -165,15 +159,11 @@ export class ApRequestService { }, }); - const response = await this.undiciFetcher.request( - url, - { - method: req.request.method, - headers: req.request.headers, - body, - }, - ); - response.body.pipe(new DevNull()); + await this.httpRequestService.send(url, { + method: req.request.method, + headers: req.request.headers, + body, + }); } /** @@ -195,13 +185,10 @@ export class ApRequestService { }, }); - const res = await this.httpRequestService.fetch( - url, - { - method: req.request.method, - headers: req.request.headers, - }, - ); + const res = await this.httpRequestService.send(url, { + method: req.request.method, + headers: req.request.headers, + }); return await res.json(); } diff --git a/packages/backend/src/core/activitypub/ApResolverService.ts b/packages/backend/src/core/activitypub/ApResolverService.ts index ca7760af81..8ead29a5f2 100644 --- a/packages/backend/src/core/activitypub/ApResolverService.ts +++ b/packages/backend/src/core/activitypub/ApResolverService.ts @@ -4,7 +4,7 @@ import { InstanceActorService } from '@/core/InstanceActorService.js'; import type { NotesRepository, PollsRepository, NoteReactionsRepository, UsersRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; import { MetaService } from '@/core/MetaService.js'; -import { HttpRequestService, UndiciFetcher } from '@/core/HttpRequestService.js'; +import { HttpRequestService } from '@/core/HttpRequestService.js'; import { DI } from '@/di-symbols.js'; import { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; @@ -19,7 +19,6 @@ import type { IObject, ICollection, IOrderedCollection } from './type.js'; export class Resolver { private history: Set; private user?: ILocalUser; - private undiciFetcher: UndiciFetcher; private logger: Logger; constructor( @@ -39,10 +38,7 @@ export class Resolver { private recursionLimit = 100, ) { this.history = new Set(); - this.logger = this.loggerService?.getLogger('ap-resolve'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる - this.undiciFetcher = this.httpRequestService.createFetcher({ - maxRedirections: 0, - }, {}, this.logger); + this.logger = this.loggerService.getLogger('ap-resolve'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる } @bindThis @@ -106,7 +102,7 @@ export class Resolver { const object = (this.user ? await this.apRequestService.signedGet(value, this.user) as IObject - : await this.undiciFetcher.getJson(value, 'application/activity+json, application/ld+json')); + : await this.httpRequestService.getJson(value, 'application/activity+json, application/ld+json')) as IObject; if (object == null || ( Array.isArray(object['@context']) ? diff --git a/packages/backend/src/core/activitypub/LdSignatureService.ts b/packages/backend/src/core/activitypub/LdSignatureService.ts index 4e4b7dce2d..5a1e01574d 100644 --- a/packages/backend/src/core/activitypub/LdSignatureService.ts +++ b/packages/backend/src/core/activitypub/LdSignatureService.ts @@ -9,7 +9,7 @@ import { CONTEXTS } from './misc/contexts.js'; class LdSignature { public debug = false; public preLoad = true; - public loderTimeout = 10 * 1000; + public loderTimeout = 5000; constructor( private httpRequestService: HttpRequestService, @@ -115,19 +115,12 @@ class LdSignature { @bindThis private async fetchDocument(url: string) { - const json = await this.httpRequestService.fetch( - url, - { - headers: { - Accept: 'application/ld+json, application/json', - }, - // TODO - //timeout: this.loderTimeout, + const json = await this.httpRequestService.send(url, { + headers: { + Accept: 'application/ld+json, application/json', }, - { - noOkError: true, - } - ).then(res => { + timeout: this.loderTimeout, + }, { throwErrorWhenResponseNotOk: false }).then(res => { if (!res.ok) { throw `${res.status} ${res.statusText}`; } else { diff --git a/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts b/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts index f0543a5ed1..57210b25d2 100644 --- a/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts +++ b/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts @@ -6,10 +6,10 @@ import type { Config } from '@/config.js'; import type Logger from '@/logger.js'; import { HttpRequestService } from '@/core/HttpRequestService.js'; import { StatusError } from '@/misc/status-error.js'; +import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; import type Bull from 'bull'; import type { WebhookDeliverJobData } from '../types.js'; -import { bindThis } from '@/decorators.js'; @Injectable() export class WebhookDeliverProcessorService { @@ -33,26 +33,23 @@ export class WebhookDeliverProcessorService { try { this.logger.debug(`delivering ${job.data.webhookId}`); - const res = await this.httpRequestService.fetch( - job.data.to, - { - method: 'POST', - headers: { - 'User-Agent': 'Misskey-Hooks', - 'X-Misskey-Host': this.config.host, - 'X-Misskey-Hook-Id': job.data.webhookId, - 'X-Misskey-Hook-Secret': job.data.secret, - }, - body: JSON.stringify({ - hookId: job.data.webhookId, - userId: job.data.userId, - eventId: job.data.eventId, - createdAt: job.data.createdAt, - type: job.data.type, - body: job.data.content, - }), - } - ); + const res = await this.httpRequestService.send(job.data.to, { + method: 'POST', + headers: { + 'User-Agent': 'Misskey-Hooks', + 'X-Misskey-Host': this.config.host, + 'X-Misskey-Hook-Id': job.data.webhookId, + 'X-Misskey-Hook-Secret': job.data.secret, + }, + body: JSON.stringify({ + hookId: job.data.webhookId, + userId: job.data.userId, + eventId: job.data.eventId, + createdAt: job.data.createdAt, + type: job.data.type, + body: job.data.content, + }), + }); this.webhooksRepository.update({ id: job.data.webhookId }, { latestSentAt: new Date(), diff --git a/packages/backend/src/server/api/endpoints/fetch-rss.ts b/packages/backend/src/server/api/endpoints/fetch-rss.ts index ae6a87513d..5849d3111f 100644 --- a/packages/backend/src/server/api/endpoints/fetch-rss.ts +++ b/packages/backend/src/server/api/endpoints/fetch-rss.ts @@ -33,16 +33,13 @@ export default class extends Endpoint { private httpRequestService: HttpRequestService, ) { super(meta, paramDef, async (ps, me) => { - const res = await this.httpRequestService.fetch( - ps.url, - { - method: 'GET', - headers: { - Accept: 'application/rss+xml, */*', - }, - // timeout: 5000, - } - ); + const res = await this.httpRequestService.send(ps.url, { + method: 'GET', + headers: { + Accept: 'application/rss+xml, */*', + }, + timeout: 5000, + }); const text = await res.text(); diff --git a/packages/backend/src/server/api/endpoints/notes/translate.ts b/packages/backend/src/server/api/endpoints/notes/translate.ts index ab19771676..66655234a1 100644 --- a/packages/backend/src/server/api/endpoints/notes/translate.ts +++ b/packages/backend/src/server/api/endpoints/notes/translate.ts @@ -7,8 +7,8 @@ import { DI } from '@/di-symbols.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { MetaService } from '@/core/MetaService.js'; import { HttpRequestService } from '@/core/HttpRequestService.js'; -import { ApiError } from '../../error.js'; import { GetterService } from '@/server/api/GetterService.js'; +import { ApiError } from '../../error.js'; export const meta = { tags: ['notes'], @@ -83,20 +83,14 @@ export default class extends Endpoint { const endpoint = instance.deeplIsPro ? 'https://api.deepl.com/v2/translate' : 'https://api-free.deepl.com/v2/translate'; - const res = await this.httpRequestService.fetch( - endpoint, - { - method: 'POST', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - Accept: 'application/json, */*', - }, - body: params.toString(), + const res = await this.httpRequestService.send(endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + Accept: 'application/json, */*', }, - { - noOkError: false, - } - ); + body: params.toString(), + }); const json = (await res.json()) as { translations: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3fdaf1449a..bfe98f9a84 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -142,7 +142,7 @@ importers: file-type: 18.2.0 fluent-ffmpeg: 2.1.2 form-data: ^4.0.0 - got: 12.5.3 + got: ^12.5.3 hpagent: 1.2.0 ioredis: 4.28.5 ip-cidr: 3.0.11 @@ -201,7 +201,6 @@ importers: typeorm: 0.3.11 typescript: 4.9.4 ulid: 2.3.0 - undici: ^5.16.0 unzipper: 0.10.11 uuid: 9.0.0 vary: 1.1.2 @@ -306,7 +305,6 @@ importers: typeorm: 0.3.11_ioredis@4.28.5+pg@8.8.0 typescript: 4.9.4 ulid: 2.3.0 - undici: 5.16.0 unzipper: 0.10.11 uuid: 9.0.0 vary: 1.1.2 From 30dce42e039c372b3cb584d97dd6e0878b614f6a Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 25 Jan 2023 12:17:53 +0900 Subject: [PATCH 14/20] fix deps --- packages/backend/package.json | 6 +++--- pnpm-lock.yaml | 10 ++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index 586b95f2e5..c3b45f6bf4 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -125,7 +125,8 @@ "web-push": "3.5.0", "websocket": "1.0.34", "ws": "8.12.0", - "xev": "3.0.2" + "xev": "3.0.2", + "node-fetch": "3.3.0" }, "devDependencies": { "@redocly/openapi-core": "1.0.0-beta.120", @@ -181,7 +182,6 @@ "eslint-plugin-import": "2.27.5", "execa": "6.1.0", "jest": "29.3.1", - "jest-mock": "^29.3.1", - "node-fetch": "3.3.0" + "jest-mock": "^29.3.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bfe98f9a84..a6b7699e2c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -264,6 +264,7 @@ importers: misskey-js: 0.0.14 ms: 3.0.0-canary.1 nested-property: 4.0.0 + node-fetch: 3.3.0 nodemailer: 6.9.0 nsfwjs: 2.4.2_@tensorflow+tfjs@4.2.0 oauth: 0.10.0 @@ -370,7 +371,6 @@ importers: execa: 6.1.0 jest: 29.3.1_@types+node@18.11.18 jest-mock: 29.3.1 - node-fetch: 3.3.0 packages/frontend: specifiers: @@ -3799,7 +3799,7 @@ packages: /axios/0.24.0: resolution: {integrity: sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==} dependencies: - follow-redirects: 1.15.2_debug@4.3.4 + follow-redirects: 1.15.2 transitivePeerDependencies: - debug dev: false @@ -3807,7 +3807,7 @@ packages: /axios/0.27.2_debug@4.3.4: resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==} dependencies: - follow-redirects: 1.15.2_debug@4.3.4 + follow-redirects: 1.15.2 form-data: 4.0.0 transitivePeerDependencies: - debug @@ -6971,7 +6971,7 @@ packages: readable-stream: 2.3.7 dev: false - /follow-redirects/1.15.2_debug@4.3.4: + /follow-redirects/1.15.2: resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} engines: {node: '>=4.0'} peerDependencies: @@ -6979,8 +6979,6 @@ packages: peerDependenciesMeta: debug: optional: true - dependencies: - debug: 4.3.4 /for-each/0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} From 945c50db1f2e2e2a3612ee327adc5575da4b5ccb Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 25 Jan 2023 12:31:03 +0900 Subject: [PATCH 15/20] Update ApRequestService.ts --- packages/backend/src/core/activitypub/ApRequestService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/core/activitypub/ApRequestService.ts b/packages/backend/src/core/activitypub/ApRequestService.ts index b949f34841..bfd53dfabf 100644 --- a/packages/backend/src/core/activitypub/ApRequestService.ts +++ b/packages/backend/src/core/activitypub/ApRequestService.ts @@ -40,7 +40,8 @@ export class ApRequestService { private httpRequestService: HttpRequestService, private loggerService: LoggerService, ) { - this.logger = this.loggerService.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + this.logger = this.loggerService?.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる } @bindThis From 3ba5541a6623fc1256c51aade666fd5cdef5c073 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 25 Jan 2023 12:36:39 +0900 Subject: [PATCH 16/20] Update ApResolverService.ts --- packages/backend/src/core/activitypub/ApResolverService.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/core/activitypub/ApResolverService.ts b/packages/backend/src/core/activitypub/ApResolverService.ts index 8ead29a5f2..7e962cb127 100644 --- a/packages/backend/src/core/activitypub/ApResolverService.ts +++ b/packages/backend/src/core/activitypub/ApResolverService.ts @@ -38,7 +38,8 @@ export class Resolver { private recursionLimit = 100, ) { this.history = new Set(); - this.logger = this.loggerService.getLogger('ap-resolve'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + this.logger = this.loggerService?.getLogger('ap-resolve'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる } @bindThis From e3275e916b92d05241bff4b1391d6166c4ab1ec1 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 25 Jan 2023 15:15:15 +0900 Subject: [PATCH 17/20] =?UTF-8?q?fix(client):=20MFM=E3=81=AEposition?= =?UTF-8?q?=E3=80=81rotate=E3=80=81scale=E3=81=A7=E5=B0=8F=E6=95=B0?= =?UTF-8?q?=E3=81=8C=E4=BD=BF=E3=81=88=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/mfm.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/frontend/src/components/mfm.ts b/packages/frontend/src/components/mfm.ts index 91875de9cf..b9ed9002ac 100644 --- a/packages/frontend/src/components/mfm.ts +++ b/packages/frontend/src/components/mfm.ts @@ -190,19 +190,19 @@ export default defineComponent({ return h(MkSparkle, {}, genEl(token.children)); } case 'rotate': { - const degrees = parseInt(token.props.args.deg) ?? '90'; + const degrees = parseFloat(token.props.args.deg) ?? '90'; style = `transform: rotate(${degrees}deg); transform-origin: center center;`; break; } case 'position': { - const x = parseInt(token.props.args.x ?? '0'); - const y = parseInt(token.props.args.y ?? '0'); + const x = parseFloat(token.props.args.x ?? '0'); + const y = parseFloat(token.props.args.y ?? '0'); style = `transform: translateX(${x}em) translateY(${y}em);`; break; } case 'scale': { - const x = Math.min(parseInt(token.props.args.x ?? '1'), 5); - const y = Math.min(parseInt(token.props.args.y ?? '1'), 5); + const x = Math.min(parseFloat(token.props.args.x ?? '1'), 5); + const y = Math.min(parseFloat(token.props.args.y ?? '1'), 5); style = `transform: scale(${x}, ${y});`; break; } From 6721d4216c6276d921fa853d4246d06f1ae2cfc6 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 25 Jan 2023 15:15:29 +0900 Subject: [PATCH 18/20] New Crowdin updates (#9716) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (Ukrainian) * New translations ja-JP.yml (Ukrainian) --- locales/uk-UA.yml | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index f000337f3b..a77bfa4f8d 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -901,6 +901,7 @@ show: "Відображення" color: "Колір" achievements: "Досягнення" _achievements: + earnedAt: "Відкрито" _types: _notes1: title: "налаштовую свій msky" @@ -954,30 +955,72 @@ _achievements: flavor: "Так багато потрібно сказати?" _login3: title: "Новачок I" + description: "3 дні користування загально" _login7: title: "Новачок II" + description: "7 днів користування загально" _login15: title: "Новачок III" + description: "15 днів користування загально" _login30: title: "Міскієць I" + description: "30 днів користування загально" _login60: title: "Міскієць II" + description: "60 днів користування загально" _login100: title: "Міскієць III" + description: "100 днів користування загально" _login200: title: "Завсідник I" + description: "200 днів користування загально" _login300: title: "Завсідник II" + description: "300 днів користування загально" _login400: title: "Завсідник III" + description: "400 днів користування загально" _login500: title: "Ветеран I" + description: "500 днів користування загально" _login600: title: "Ветеран II" + description: "600 днів користування загально" _login700: title: "Ветеран III" + description: "700 днів користування загально" + _login800: + description: "800 днів користування загально" + _login900: + description: "900 днів користування загально" _login1000: + description: "1000 днів користування загально" flavor: "Дякуємо, що користуєтеся Misskey!" + _following50: + description: "Кількість підписок сягнула 50" + _following100: + title: "100 друзів" + description: "Кількість підписок сягнула 100" + _following300: + title: "Надлишок друзів" + description: "Кількість підписок сягнула 300" + _followers1: + title: "Перший підписник" + description: "З'явився перший підписник" + _followers10: + title: "Follow me!" + description: "Кількість підписників досягла 10" + _followers50: + description: "Кількість підписників досягла 50" + _followers100: + description: "Кількість підписників досягла 100" + _followers300: + description: "Кількість підписників досягла 300" + _followers500: + description: "Кількість підписників досягла 500" + _followers1000: + title: "Інфлюенсер" + description: "Кількість підписників досягла 1000" _passedSinceAccountCreated3: description: "Минуло 3 роки з моменту створення акаунта" _loggedInOnBirthday: From 35fd523edfd7b1b7dfedb5ceb04266f4c2376274 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 25 Jan 2023 15:15:59 +0900 Subject: [PATCH 19/20] 13.2.2 --- CHANGELOG.md | 8 ++++++++ package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f2d8ad378..8dd21ce6d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,14 @@ You should also include the user name that made the change. --> +## 13.2.2 (2023/01/25) +### Improvements +- サーバーのパフォーマンスを改善 + +### Bugfixes +- サインイン時に誤ったレートリミットがかかることがある問題を修正 +- MFMのposition、rotate、scaleで小数が使えない問題を修正 + ## 13.2.1 (2023/01/24) ### Improvements - デザインの調整 diff --git a/package.json b/package.json index 32f1f83943..800ca39efa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.2.1", + "version": "13.2.2", "codename": "nasubi", "repository": { "type": "git", From 5f49ac1b11ab7927ab17df2bd8a30eaf803e94f4 Mon Sep 17 00:00:00 2001 From: tamaina Date: Wed, 25 Jan 2023 06:21:08 +0000 Subject: [PATCH 20/20] =?UTF-8?q?fix(client):=20=E3=82=A2=E3=83=8B?= =?UTF-8?q?=E3=83=A1=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92=E3=82=AA?= =?UTF-8?q?=E3=83=95=E3=81=AB=E8=A8=AD=E5=AE=9A=E3=81=97=E3=81=A6=E3=82=82?= =?UTF-8?q?=E7=B5=B5=E6=96=87=E5=AD=97=E3=81=AE=E3=82=A2=E3=83=8B=E3=83=A1?= =?UTF-8?q?=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E3=81=8C=E6=AD=A2=E3=81=BE?= =?UTF-8?q?=E3=82=89=E3=81=AA=E3=81=84=20Fix=20#9720?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/global/MkEmoji.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/global/MkEmoji.vue b/packages/frontend/src/components/global/MkEmoji.vue index 93f50da20e..991c6fb7ca 100644 --- a/packages/frontend/src/components/global/MkEmoji.vue +++ b/packages/frontend/src/components/global/MkEmoji.vue @@ -33,7 +33,7 @@ const url = computed(() => { return char2path(char.value); } else if (props.host == null && !customEmojiName.includes('@')) { const found = customEmojis.find(x => x.name === customEmojiName); - return found ? found.url : null; + return found ? defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(found.url) : found.url : null; } else { const rawUrl = props.host ? `/emoji/${customEmojiName}@${props.host}.webp` : `/emoji/${customEmojiName}.webp`; return defaultStore.state.disableShowingAnimatedImages