Merge branch 'develop' into mahjong
This commit is contained in:
		| @@ -1,4 +0,0 @@ | ||||
| node_modules | ||||
| /built | ||||
| /.eslintrc.js | ||||
| /@types/**/* | ||||
| @@ -1,32 +0,0 @@ | ||||
| module.exports = { | ||||
| 	parserOptions: { | ||||
| 		tsconfigRootDir: __dirname, | ||||
| 		project: ['./tsconfig.json', './test/tsconfig.json'], | ||||
| 	}, | ||||
| 	extends: [ | ||||
| 		'../shared/.eslintrc.js', | ||||
| 	], | ||||
| 	rules: { | ||||
| 		'import/order': ['warn', { | ||||
| 			'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'], | ||||
| 			'pathGroups': [ | ||||
| 				{ | ||||
| 					'pattern': '@/**', | ||||
| 					'group': 'external', | ||||
| 					'position': 'after' | ||||
| 				} | ||||
| 			], | ||||
| 		}], | ||||
| 		'no-restricted-globals': [ | ||||
| 			'error', | ||||
| 			{ | ||||
| 				'name': '__dirname', | ||||
| 				'message': 'Not in ESModule. Use `import.meta.url` instead.' | ||||
| 			}, | ||||
| 			{ | ||||
| 				'name': '__filename', | ||||
| 				'message': 'Not in ESModule. Use `import.meta.url` instead.' | ||||
| 			} | ||||
| 	] | ||||
| 	}, | ||||
| }; | ||||
							
								
								
									
										46
									
								
								packages/backend/eslint.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								packages/backend/eslint.config.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| import tsParser from '@typescript-eslint/parser'; | ||||
| import sharedConfig from '../shared/eslint.config.js'; | ||||
|  | ||||
| export default [ | ||||
| 	...sharedConfig, | ||||
| 	{ | ||||
| 		ignores: ['**/node_modules', 'built', '@types/**/*'], | ||||
| 	}, | ||||
| 	{ | ||||
| 		files: ['**/*.ts', '**/*.tsx'], | ||||
| 		languageOptions: { | ||||
| 			parserOptions: { | ||||
| 				parser: tsParser, | ||||
| 				project: ['./tsconfig.json', './test/tsconfig.json'], | ||||
| 				sourceType: 'module', | ||||
| 				tsconfigRootDir: import.meta.dirname, | ||||
| 			}, | ||||
| 		}, | ||||
| 		rules: { | ||||
| 			'import/order': ['warn', { | ||||
| 				groups: [ | ||||
| 					'builtin', | ||||
| 					'external', | ||||
| 					'internal', | ||||
| 					'parent', | ||||
| 					'sibling', | ||||
| 					'index', | ||||
| 					'object', | ||||
| 					'type', | ||||
| 				], | ||||
| 				pathGroups: [{ | ||||
| 					pattern: '@/**', | ||||
| 					group: 'external', | ||||
| 					position: 'after', | ||||
| 				}], | ||||
| 			}], | ||||
| 			'no-restricted-globals': ['error', { | ||||
| 				name: '__dirname', | ||||
| 				message: 'Not in ESModule. Use `import.meta.url` instead.', | ||||
| 			}, { | ||||
| 				name: '__filename', | ||||
| 				message: 'Not in ESModule. Use `import.meta.url` instead.', | ||||
| 			}], | ||||
| 		}, | ||||
| 	}, | ||||
| ]; | ||||
| @@ -65,43 +65,43 @@ | ||||
| 		"utf-8-validate": "6.0.3" | ||||
| 	}, | ||||
| 	"dependencies": { | ||||
| 		"@aws-sdk/client-s3": "3.412.0", | ||||
| 		"@aws-sdk/lib-storage": "3.412.0", | ||||
| 		"@bull-board/api": "5.17.0", | ||||
| 		"@bull-board/fastify": "5.17.0", | ||||
| 		"@bull-board/ui": "5.17.0", | ||||
| 		"@aws-sdk/client-s3": "3.600.0", | ||||
| 		"@aws-sdk/lib-storage": "3.600.0", | ||||
| 		"@bull-board/api": "5.20.5", | ||||
| 		"@bull-board/fastify": "5.20.5", | ||||
| 		"@bull-board/ui": "5.20.5", | ||||
| 		"@discordapp/twemoji": "15.0.3", | ||||
| 		"@fastify/accepts": "4.3.0", | ||||
| 		"@fastify/cookie": "9.3.1", | ||||
| 		"@fastify/cors": "9.0.1", | ||||
| 		"@fastify/express": "3.0.0", | ||||
| 		"@fastify/http-proxy": "9.5.0", | ||||
| 		"@fastify/multipart": "8.2.0", | ||||
| 		"@fastify/static": "7.0.3", | ||||
| 		"@fastify/multipart": "8.3.0", | ||||
| 		"@fastify/static": "7.0.4", | ||||
| 		"@fastify/view": "9.1.0", | ||||
| 		"@misskey-dev/sharp-read-bmp": "1.2.0", | ||||
| 		"@misskey-dev/summaly": "5.1.0", | ||||
| 		"@napi-rs/canvas": "^0.1.52", | ||||
| 		"@nestjs/common": "10.3.8", | ||||
| 		"@nestjs/core": "10.3.8", | ||||
| 		"@nestjs/testing": "10.3.8", | ||||
| 		"@napi-rs/canvas": "^0.1.53", | ||||
| 		"@nestjs/common": "10.3.10", | ||||
| 		"@nestjs/core": "10.3.10", | ||||
| 		"@nestjs/testing": "10.3.10", | ||||
| 		"@peertube/http-signature": "1.7.0", | ||||
| 		"@sentry/node": "^8.5.0", | ||||
| 		"@sentry/profiling-node": "^8.5.0", | ||||
| 		"@sentry/node": "8.13.0", | ||||
| 		"@sentry/profiling-node": "8.13.0", | ||||
| 		"@simplewebauthn/server": "10.0.0", | ||||
| 		"@sinonjs/fake-timers": "11.2.2", | ||||
| 		"@smithy/node-http-handler": "2.5.0", | ||||
| 		"@swc/cli": "0.3.12", | ||||
| 		"@swc/core": "1.4.17", | ||||
| 		"@swc/core": "1.6.6", | ||||
| 		"@twemoji/parser": "15.1.1", | ||||
| 		"accepts": "1.3.8", | ||||
| 		"ajv": "8.13.0", | ||||
| 		"ajv": "8.16.0", | ||||
| 		"archiver": "7.0.1", | ||||
| 		"async-mutex": "0.5.0", | ||||
| 		"bcryptjs": "2.4.3", | ||||
| 		"blurhash": "2.0.5", | ||||
| 		"body-parser": "1.20.2", | ||||
| 		"bullmq": "5.7.8", | ||||
| 		"bullmq": "5.8.3", | ||||
| 		"cacheable-lookup": "7.0.0", | ||||
| 		"cbor": "9.0.2", | ||||
| 		"chalk": "5.3.0", | ||||
| @@ -112,27 +112,27 @@ | ||||
| 		"content-disposition": "0.5.4", | ||||
| 		"date-fns": "2.30.0", | ||||
| 		"deep-email-validator": "0.1.21", | ||||
| 		"fastify": "4.26.2", | ||||
| 		"fastify": "4.28.1", | ||||
| 		"fastify-raw-body": "4.3.0", | ||||
| 		"feed": "4.2.2", | ||||
| 		"file-type": "19.0.0", | ||||
| 		"fluent-ffmpeg": "2.1.2", | ||||
| 		"fluent-ffmpeg": "2.1.3", | ||||
| 		"form-data": "4.0.0", | ||||
| 		"got": "14.2.1", | ||||
| 		"got": "14.4.1", | ||||
| 		"happy-dom": "10.0.3", | ||||
| 		"hpagent": "1.2.0", | ||||
| 		"htmlescape": "1.1.1", | ||||
| 		"http-link-header": "1.1.3", | ||||
| 		"ioredis": "5.4.1", | ||||
| 		"ip-cidr": "3.1.0", | ||||
| 		"ip-cidr": "4.0.1", | ||||
| 		"ipaddr.js": "2.2.0", | ||||
| 		"is-svg": "5.0.0", | ||||
| 		"is-svg": "5.0.1", | ||||
| 		"js-yaml": "4.1.0", | ||||
| 		"jsdom": "24.0.0", | ||||
| 		"jsdom": "24.1.0", | ||||
| 		"json5": "2.2.3", | ||||
| 		"jsonld": "8.3.2", | ||||
| 		"jsrsasign": "11.1.0", | ||||
| 		"meilisearch": "0.38.0", | ||||
| 		"meilisearch": "0.41.0", | ||||
| 		"mfm-js": "0.24.0", | ||||
| 		"microformats-parser": "2.0.2", | ||||
| 		"mime-types": "2.1.35", | ||||
| @@ -143,24 +143,24 @@ | ||||
| 		"nanoid": "5.0.7", | ||||
| 		"nested-property": "4.0.0", | ||||
| 		"node-fetch": "3.3.2", | ||||
| 		"nodemailer": "6.9.13", | ||||
| 		"nodemailer": "6.9.14", | ||||
| 		"nsfwjs": "2.4.2", | ||||
| 		"oauth": "0.10.0", | ||||
| 		"oauth2orize": "1.12.0", | ||||
| 		"oauth2orize-pkce": "0.1.2", | ||||
| 		"os-utils": "0.0.14", | ||||
| 		"otpauth": "9.2.3", | ||||
| 		"otpauth": "9.3.1", | ||||
| 		"parse5": "7.1.2", | ||||
| 		"pg": "8.11.5", | ||||
| 		"pg": "8.12.0", | ||||
| 		"pkce-challenge": "4.1.0", | ||||
| 		"probe-image-size": "7.2.3", | ||||
| 		"promise-limit": "2.7.0", | ||||
| 		"pug": "3.0.2", | ||||
| 		"pug": "3.0.3", | ||||
| 		"punycode": "2.3.1", | ||||
| 		"qrcode": "1.5.3", | ||||
| 		"random-seed": "0.3.0", | ||||
| 		"ratelimiter": "3.4.1", | ||||
| 		"re2": "1.21.2", | ||||
| 		"re2": "1.21.3", | ||||
| 		"redis-lock": "0.1.4", | ||||
| 		"reflect-metadata": "0.2.2", | ||||
| 		"rename": "1.0.4", | ||||
| @@ -168,27 +168,26 @@ | ||||
| 		"rxjs": "7.8.1", | ||||
| 		"sanitize-html": "2.13.0", | ||||
| 		"secure-json-parse": "2.7.0", | ||||
| 		"sharp": "0.33.3", | ||||
| 		"sharp": "0.33.4", | ||||
| 		"slacc": "0.0.10", | ||||
| 		"strict-event-emitter-types": "2.0.0", | ||||
| 		"stringz": "2.1.0", | ||||
| 		"systeminformation": "5.22.7", | ||||
| 		"systeminformation": "5.22.11", | ||||
| 		"tinycolor2": "1.6.0", | ||||
| 		"tmp": "0.2.3", | ||||
| 		"tsc-alias": "1.8.8", | ||||
| 		"tsc-alias": "1.8.10", | ||||
| 		"tsconfig-paths": "4.2.0", | ||||
| 		"typeorm": "0.3.20", | ||||
| 		"typescript": "5.5.2", | ||||
| 		"typescript": "5.5.3", | ||||
| 		"ulid": "2.3.0", | ||||
| 		"vary": "1.1.2", | ||||
| 		"web-push": "3.6.7", | ||||
| 		"ws": "8.17.0", | ||||
| 		"ws": "8.17.1", | ||||
| 		"xev": "3.0.2" | ||||
| 	}, | ||||
| 	"devDependencies": { | ||||
| 		"@jest/globals": "29.7.0", | ||||
| 		"@misskey-dev/eslint-plugin": "1.0.0", | ||||
| 		"@nestjs/platform-express": "10.3.8", | ||||
| 		"@nestjs/platform-express": "10.3.10", | ||||
| 		"@simplewebauthn/types": "10.0.0", | ||||
| 		"@swc/jest": "0.2.36", | ||||
| 		"@types/accepts": "1.3.7", | ||||
| @@ -198,21 +197,21 @@ | ||||
| 		"@types/color-convert": "2.0.3", | ||||
| 		"@types/content-disposition": "0.5.8", | ||||
| 		"@types/fluent-ffmpeg": "2.1.24", | ||||
| 		"@types/htmlescape": "^1.1.3", | ||||
| 		"@types/http-link-header": "1.0.5", | ||||
| 		"@types/htmlescape": "1.1.3", | ||||
| 		"@types/http-link-header": "1.0.7", | ||||
| 		"@types/jest": "29.5.12", | ||||
| 		"@types/js-yaml": "4.0.9", | ||||
| 		"@types/jsdom": "21.1.6", | ||||
| 		"@types/jsonld": "1.5.13", | ||||
| 		"@types/jsdom": "21.1.7", | ||||
| 		"@types/jsonld": "1.5.14", | ||||
| 		"@types/jsrsasign": "10.5.14", | ||||
| 		"@types/mime-types": "2.1.4", | ||||
| 		"@types/ms": "0.7.34", | ||||
| 		"@types/node": "20.12.7", | ||||
| 		"@types/node": "20.14.9", | ||||
| 		"@types/nodemailer": "6.4.15", | ||||
| 		"@types/oauth": "0.9.4", | ||||
| 		"@types/oauth": "0.9.5", | ||||
| 		"@types/oauth2orize": "1.11.5", | ||||
| 		"@types/oauth2orize-pkce": "0.1.2", | ||||
| 		"@types/pg": "8.11.5", | ||||
| 		"@types/pg": "8.11.6", | ||||
| 		"@types/pug": "2.0.10", | ||||
| 		"@types/punycode": "2.1.4", | ||||
| 		"@types/qrcode": "1.5.5", | ||||
| @@ -228,18 +227,17 @@ | ||||
| 		"@types/vary": "1.1.3", | ||||
| 		"@types/web-push": "3.6.3", | ||||
| 		"@types/ws": "8.5.10", | ||||
| 		"@typescript-eslint/eslint-plugin": "7.7.1", | ||||
| 		"@typescript-eslint/parser": "7.7.1", | ||||
| 		"aws-sdk-client-mock": "3.0.1", | ||||
| 		"@typescript-eslint/eslint-plugin": "7.15.0", | ||||
| 		"@typescript-eslint/parser": "7.15.0", | ||||
| 		"aws-sdk-client-mock": "4.0.1", | ||||
| 		"cross-env": "7.0.3", | ||||
| 		"eslint": "8.57.0", | ||||
| 		"eslint-plugin-import": "2.29.1", | ||||
| 		"execa": "8.0.1", | ||||
| 		"fkill": "^9.0.0", | ||||
| 		"execa": "9.2.0", | ||||
| 		"fkill": "9.0.0", | ||||
| 		"jest": "29.7.0", | ||||
| 		"jest-mock": "29.7.0", | ||||
| 		"nodemon": "3.1.0", | ||||
| 		"nodemon": "3.1.4", | ||||
| 		"pid-port": "1.0.0", | ||||
| 		"simple-oauth2": "5.0.0" | ||||
| 		"simple-oauth2": "5.0.1" | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -30,6 +30,7 @@ function execStart() { | ||||
|  | ||||
| async function killProc() { | ||||
| 	if (backendProcess) { | ||||
| 		backendProcess.catch(() => {}); // backendProcess.kill()によって発生する例外を無視するためにcatch()を呼び出す | ||||
| 		backendProcess.kill(); | ||||
| 		await new Promise(resolve => backendProcess.on('exit', resolve)); | ||||
| 		backendProcess = undefined; | ||||
| @@ -46,6 +47,7 @@ async function killProc() { | ||||
| 		], | ||||
| 		{ | ||||
| 			stdio: [process.stdin, process.stdout, process.stderr, 'ipc'], | ||||
| 			serialization: "json", | ||||
| 		}) | ||||
| 		.on('message', async (message) => { | ||||
| 			if (message.type === 'exit') { | ||||
|   | ||||
| @@ -13,10 +13,12 @@ import { intersperse } from '@/misc/prelude/array.js'; | ||||
| import { normalizeForSearch } from '@/misc/normalize-for-search.js'; | ||||
| import type { IMentionedRemoteUsers } from '@/models/Note.js'; | ||||
| import { bindThis } from '@/decorators.js'; | ||||
| import * as TreeAdapter from '../../node_modules/parse5/dist/tree-adapters/default.js'; | ||||
| import type { DefaultTreeAdapterMap } from 'parse5'; | ||||
| import type * as mfm from 'mfm-js'; | ||||
|  | ||||
| const treeAdapter = TreeAdapter.defaultTreeAdapter; | ||||
| const treeAdapter = parse5.defaultTreeAdapter; | ||||
| type Node = DefaultTreeAdapterMap['node']; | ||||
| type ChildNode = DefaultTreeAdapterMap['childNode']; | ||||
|  | ||||
| const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/; | ||||
| const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/; | ||||
| @@ -46,7 +48,7 @@ export class MfmService { | ||||
|  | ||||
| 		return text.trim(); | ||||
|  | ||||
| 		function getText(node: TreeAdapter.Node): string { | ||||
| 		function getText(node: Node): string { | ||||
| 			if (treeAdapter.isTextNode(node)) return node.value; | ||||
| 			if (!treeAdapter.isElementNode(node)) return ''; | ||||
| 			if (node.nodeName === 'br') return '\n'; | ||||
| @@ -58,7 +60,7 @@ export class MfmService { | ||||
| 			return ''; | ||||
| 		} | ||||
|  | ||||
| 		function appendChildren(childNodes: TreeAdapter.ChildNode[]): void { | ||||
| 		function appendChildren(childNodes: ChildNode[]): void { | ||||
| 			if (childNodes) { | ||||
| 				for (const n of childNodes) { | ||||
| 					analyze(n); | ||||
| @@ -66,14 +68,16 @@ export class MfmService { | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		function analyze(node: TreeAdapter.Node) { | ||||
| 		function analyze(node: Node) { | ||||
| 			if (treeAdapter.isTextNode(node)) { | ||||
| 				text += node.value; | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			// Skip comment or document type node | ||||
| 			if (!treeAdapter.isElementNode(node)) return; | ||||
| 			if (!treeAdapter.isElementNode(node)) { | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			switch (node.nodeName) { | ||||
| 				case 'br': { | ||||
| @@ -81,8 +85,7 @@ export class MfmService { | ||||
| 					break; | ||||
| 				} | ||||
|  | ||||
| 				case 'a': | ||||
| 				{ | ||||
| 				case 'a': { | ||||
| 					const txt = getText(node); | ||||
| 					const rel = node.attrs.find(x => x.name === 'rel'); | ||||
| 					const href = node.attrs.find(x => x.name === 'href'); | ||||
| @@ -90,7 +93,7 @@ export class MfmService { | ||||
| 					// ハッシュタグ | ||||
| 					if (normalizedHashtagNames && href && normalizedHashtagNames.has(normalizeForSearch(txt))) { | ||||
| 						text += txt; | ||||
| 					// メンション | ||||
| 						// メンション | ||||
| 					} else if (txt.startsWith('@') && !(rel && rel.value.startsWith('me '))) { | ||||
| 						const part = txt.split('@'); | ||||
|  | ||||
| @@ -102,7 +105,7 @@ export class MfmService { | ||||
| 						} else if (part.length === 3) { | ||||
| 							text += txt; | ||||
| 						} | ||||
| 					// その他 | ||||
| 						// その他 | ||||
| 					} else { | ||||
| 						const generateLink = () => { | ||||
| 							if (!href && !txt) { | ||||
| @@ -130,8 +133,7 @@ export class MfmService { | ||||
| 					break; | ||||
| 				} | ||||
|  | ||||
| 				case 'h1': | ||||
| 				{ | ||||
| 				case 'h1': { | ||||
| 					text += '【'; | ||||
| 					appendChildren(node.childNodes); | ||||
| 					text += '】\n'; | ||||
| @@ -139,16 +141,14 @@ export class MfmService { | ||||
| 				} | ||||
|  | ||||
| 				case 'b': | ||||
| 				case 'strong': | ||||
| 				{ | ||||
| 				case 'strong': { | ||||
| 					text += '**'; | ||||
| 					appendChildren(node.childNodes); | ||||
| 					text += '**'; | ||||
| 					break; | ||||
| 				} | ||||
|  | ||||
| 				case 'small': | ||||
| 				{ | ||||
| 				case 'small': { | ||||
| 					text += '<small>'; | ||||
| 					appendChildren(node.childNodes); | ||||
| 					text += '</small>'; | ||||
| @@ -156,8 +156,7 @@ export class MfmService { | ||||
| 				} | ||||
|  | ||||
| 				case 's': | ||||
| 				case 'del': | ||||
| 				{ | ||||
| 				case 'del': { | ||||
| 					text += '~~'; | ||||
| 					appendChildren(node.childNodes); | ||||
| 					text += '~~'; | ||||
| @@ -165,8 +164,7 @@ export class MfmService { | ||||
| 				} | ||||
|  | ||||
| 				case 'i': | ||||
| 				case 'em': | ||||
| 				{ | ||||
| 				case 'em': { | ||||
| 					text += '<i>'; | ||||
| 					appendChildren(node.childNodes); | ||||
| 					text += '</i>'; | ||||
| @@ -207,8 +205,7 @@ export class MfmService { | ||||
| 				case 'h3': | ||||
| 				case 'h4': | ||||
| 				case 'h5': | ||||
| 				case 'h6': | ||||
| 				{ | ||||
| 				case 'h6': { | ||||
| 					text += '\n\n'; | ||||
| 					appendChildren(node.childNodes); | ||||
| 					break; | ||||
| @@ -221,8 +218,7 @@ export class MfmService { | ||||
| 				case 'article': | ||||
| 				case 'li': | ||||
| 				case 'dt': | ||||
| 				case 'dd': | ||||
| 				{ | ||||
| 				case 'dd': { | ||||
| 					text += '\n'; | ||||
| 					appendChildren(node.childNodes); | ||||
| 					break; | ||||
|   | ||||
| @@ -20,7 +20,7 @@ export const packedDriveFileSchema = { | ||||
| 		name: { | ||||
| 			type: 'string', | ||||
| 			optional: false, nullable: false, | ||||
| 			example: 'lenna.jpg', | ||||
| 			example: '192.jpg', | ||||
| 		}, | ||||
| 		type: { | ||||
| 			type: 'string', | ||||
|   | ||||
| @@ -61,7 +61,7 @@ export const meta = { | ||||
| 			name: { | ||||
| 				type: 'string', | ||||
| 				optional: false, nullable: false, | ||||
| 				example: 'lenna.jpg', | ||||
| 				example: '192.jpg', | ||||
| 			}, | ||||
| 			type: { | ||||
| 				type: 'string', | ||||
|   | ||||
| @@ -257,7 +257,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint- | ||||
|  | ||||
| 			const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id }); | ||||
|  | ||||
| 			if (ps.name !== undefined) updates.name = ps.name; | ||||
| 			if (ps.name !== undefined) { | ||||
| 				if (ps.name === null) { | ||||
| 					updates.name = null; | ||||
| 				} else { | ||||
| 					const trimmedName = ps.name.trim(); | ||||
| 					updates.name = trimmedName === '' ? null : trimmedName; | ||||
| 				} | ||||
| 			} | ||||
| 			if (ps.description !== undefined) profileUpdates.description = ps.description; | ||||
| 			if (ps.lang !== undefined) profileUpdates.lang = ps.lang; | ||||
| 			if (ps.location !== undefined) profileUpdates.location = ps.location; | ||||
|   | ||||
| @@ -29,7 +29,8 @@ | ||||
|  | ||||
| 	let forceError = localStorage.getItem('forceError'); | ||||
| 	if (forceError != null) { | ||||
| 		renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.') | ||||
| 		renderError('FORCED_ERROR', 'This error is forced by having forceError in local storage.'); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	//#region Detect language & fetch translations | ||||
| @@ -155,7 +156,12 @@ | ||||
| 		document.head.appendChild(css); | ||||
| 	} | ||||
|  | ||||
| 	function renderError(code, details) { | ||||
| 	async function renderError(code, details) { | ||||
| 		// Cannot set property 'innerHTML' of null を回避 | ||||
| 		if (document.readyState === 'loading') { | ||||
| 			await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve)); | ||||
| 		} | ||||
|  | ||||
| 		let errorsElement = document.getElementById('errors'); | ||||
|  | ||||
| 		if (!errorsElement) { | ||||
| @@ -314,6 +320,6 @@ | ||||
| 			#errorInfo { | ||||
| 				width: 50%; | ||||
| 			} | ||||
| 		`) | ||||
| 		}`) | ||||
| 	} | ||||
| })(); | ||||
|   | ||||
| @@ -1,32 +0,0 @@ | ||||
| module.exports = { | ||||
| 	parserOptions: { | ||||
| 		tsconfigRootDir: __dirname, | ||||
| 		project: ['./tsconfig.json'], | ||||
| 	}, | ||||
| 	extends: [ | ||||
| 		'../../shared/.eslintrc.js', | ||||
| 	], | ||||
| 	rules: { | ||||
| 		'import/order': ['warn', { | ||||
| 			'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'], | ||||
| 			'pathGroups': [ | ||||
| 				{ | ||||
| 					'pattern': '@/**', | ||||
| 					'group': 'external', | ||||
| 					'position': 'after' | ||||
| 				} | ||||
| 			], | ||||
| 		}], | ||||
| 		'no-restricted-globals': [ | ||||
| 			'error', | ||||
| 			{ | ||||
| 				'name': '__dirname', | ||||
| 				'message': 'Not in ESModule. Use `import.meta.url` instead.' | ||||
| 			}, | ||||
| 			{ | ||||
| 				'name': '__filename', | ||||
| 				'message': 'Not in ESModule. Use `import.meta.url` instead.' | ||||
| 			} | ||||
| 	] | ||||
| 	}, | ||||
| }; | ||||
							
								
								
									
										43
									
								
								packages/backend/test-server/eslint.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								packages/backend/test-server/eslint.config.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| import tsParser from '@typescript-eslint/parser'; | ||||
| import sharedConfig from '../../shared/eslint.config.js'; | ||||
|  | ||||
| export default [ | ||||
| 	...sharedConfig, | ||||
| 	{ | ||||
| 		files: ['**/*.ts', '**/*.tsx'], | ||||
| 		languageOptions: { | ||||
| 			parserOptions: { | ||||
| 				parser: tsParser, | ||||
| 				project: ['./tsconfig.json'], | ||||
| 				sourceType: 'module', | ||||
| 				tsconfigRootDir: import.meta.dirname, | ||||
| 			}, | ||||
| 		}, | ||||
| 		rules: { | ||||
| 			'import/order': ['warn', { | ||||
| 				groups: [ | ||||
| 					'builtin', | ||||
| 					'external', | ||||
| 					'internal', | ||||
| 					'parent', | ||||
| 					'sibling', | ||||
| 					'index', | ||||
| 					'object', | ||||
| 					'type', | ||||
| 				], | ||||
| 				pathGroups: [{ | ||||
| 					pattern: '@/**', | ||||
| 					group: 'external', | ||||
| 					position: 'after', | ||||
| 				}], | ||||
| 			}], | ||||
| 			'no-restricted-globals': ['error', { | ||||
| 				name: '__dirname', | ||||
| 				message: 'Not in ESModule. Use `import.meta.url` instead.', | ||||
| 			}, { | ||||
| 				name: '__filename', | ||||
| 				message: 'Not in ESModule. Use `import.meta.url` instead.', | ||||
| 			}], | ||||
| 		}, | ||||
| 	}, | ||||
| ]; | ||||
| @@ -1,11 +0,0 @@ | ||||
| module.exports = { | ||||
| 	parserOptions: { | ||||
| 		tsconfigRootDir: __dirname, | ||||
| 		project: ['./tsconfig.json'], | ||||
| 	}, | ||||
| 	extends: ['../.eslintrc.cjs'], | ||||
| 	env: { | ||||
| 		node: true, | ||||
| 		jest: true, | ||||
| 	}, | ||||
| }; | ||||
| @@ -23,7 +23,7 @@ describe('Drive', () => { | ||||
|  | ||||
| 		const marker = Math.random().toString(); | ||||
|  | ||||
| 		const url = 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg'; | ||||
| 		const url = 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.jpg'; | ||||
|  | ||||
| 		const catcher = makeStreamCatcher( | ||||
| 			alice, | ||||
| @@ -41,14 +41,14 @@ describe('Drive', () => { | ||||
| 		const file = await catcher; | ||||
|  | ||||
| 		assert.strictEqual(res.status, 204); | ||||
| 		assert.strictEqual(file.name, 'Lenna.jpg'); | ||||
| 		assert.strictEqual(file.name, '192.jpg'); | ||||
| 		assert.strictEqual(file.type, 'image/jpeg'); | ||||
| 	}); | ||||
|  | ||||
| 	test('ローカルからアップロードできる', async () => { | ||||
| 		// APIレスポンスを直接使用するので utils.js uploadFile が通過することで成功とする | ||||
|  | ||||
| 		const res = await uploadFile(alice, { path: 'Lenna.jpg', name: 'テスト画像' }); | ||||
| 		const res = await uploadFile(alice, { path: '192.jpg', name: 'テスト画像' }); | ||||
|  | ||||
| 		assert.strictEqual(res.body?.name, 'テスト画像.jpg'); | ||||
| 		assert.strictEqual(res.body.type, 'image/jpeg'); | ||||
|   | ||||
| @@ -117,12 +117,21 @@ describe('Endpoints', () => { | ||||
| 			assert.strictEqual(res.body.birthday, myBirthday); | ||||
| 		}); | ||||
|  | ||||
| 		test('名前を空白にできる', async () => { | ||||
| 		test('名前を空白のみにした場合nullになる', async () => { | ||||
| 			const res = await api('i/update', { | ||||
| 				name: ' ', | ||||
| 			}, alice); | ||||
| 			assert.strictEqual(res.status, 200); | ||||
| 			assert.strictEqual(res.body.name, ' '); | ||||
| 			assert.strictEqual(res.body.name, null); | ||||
| 		}); | ||||
|  | ||||
| 		test('名前の前後に空白(ホワイトスペース)を入れてもトリムされる', async () => { | ||||
| 			const res = await api('i/update', { | ||||
| 				// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#white_space | ||||
| 				name: ' あ い う \u0009\u000b\u000c\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff', | ||||
| 			}, alice); | ||||
| 			assert.strictEqual(res.status, 200); | ||||
| 			assert.strictEqual(res.body.name, 'あ い う'); | ||||
| 		}); | ||||
|  | ||||
| 		test('誕生日の設定を削除できる', async () => { | ||||
| @@ -584,7 +593,7 @@ describe('Endpoints', () => { | ||||
|  | ||||
| 			assert.strictEqual(res.status, 200); | ||||
| 			assert.strictEqual(typeof res.body === 'object' && !Array.isArray(res.body), true); | ||||
| 			assert.strictEqual(res.body!.name, 'Lenna.jpg'); | ||||
| 			assert.strictEqual(res.body!.name, '192.jpg'); | ||||
| 		}); | ||||
|  | ||||
| 		test('ファイルに名前を付けられる', async () => { | ||||
|   | ||||
| @@ -7,12 +7,13 @@ import { INestApplicationContext } from '@nestjs/common'; | ||||
|  | ||||
| process.env.NODE_ENV = 'test'; | ||||
|  | ||||
| import { setTimeout } from 'node:timers/promises'; | ||||
| import * as assert from 'assert'; | ||||
| import { loadConfig } from '@/config.js'; | ||||
| import { MiRepository, MiUser, UsersRepository, miRepository } from '@/models/_.js'; | ||||
| import { secureRndstr } from '@/misc/secure-rndstr.js'; | ||||
| import { jobQueue } from '@/boot/common.js'; | ||||
| import { api, initTestDb, signup, sleep, successfulApiCall, uploadFile } from '../utils.js'; | ||||
| import { api, initTestDb, signup, successfulApiCall, uploadFile } from '../utils.js'; | ||||
| import type * as misskey from 'misskey-js'; | ||||
|  | ||||
| describe('Account Move', () => { | ||||
| @@ -271,7 +272,7 @@ describe('Account Move', () => { | ||||
|  | ||||
| 			assert.strictEqual(move.status, 200); | ||||
|  | ||||
| 			await sleep(1000 * 3); // wait for jobs to finish | ||||
| 			await setTimeout(1000 * 3); // wait for jobs to finish | ||||
|  | ||||
| 			// Unfollow delayed? | ||||
| 			const aliceFollowings = await api('users/following', { | ||||
| @@ -330,7 +331,7 @@ describe('Account Move', () => { | ||||
| 		}); | ||||
|  | ||||
| 		test('Unfollowed after 10 sec (24 hours in production).', async () => { | ||||
| 			await sleep(1000 * 8); | ||||
| 			await setTimeout(1000 * 8); | ||||
|  | ||||
| 			const following = await api('users/following', { | ||||
| 				userId: alice.id, | ||||
|   | ||||
| @@ -41,7 +41,7 @@ describe('Note', () => { | ||||
| 	}); | ||||
|  | ||||
| 	test('ファイルを添付できる', async () => { | ||||
| 		const file = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg'); | ||||
| 		const file = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.jpg'); | ||||
|  | ||||
| 		const res = await api('notes/create', { | ||||
| 			fileIds: [file.id], | ||||
| @@ -53,7 +53,7 @@ describe('Note', () => { | ||||
| 	}, 1000 * 10); | ||||
|  | ||||
| 	test('他人のファイルで怒られる', async () => { | ||||
| 		const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg'); | ||||
| 		const file = await uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.jpg'); | ||||
|  | ||||
| 		const res = await api('notes/create', { | ||||
| 			text: 'test', | ||||
|   | ||||
| @@ -6,7 +6,8 @@ | ||||
| process.env.NODE_ENV = 'test'; | ||||
|  | ||||
| import * as assert from 'assert'; | ||||
| import { api, post, signup, sleep, waitFire } from '../utils.js'; | ||||
| import { setTimeout } from 'node:timers/promises'; | ||||
| import { api, post, signup, waitFire } from '../utils.js'; | ||||
| import type * as misskey from 'misskey-js'; | ||||
|  | ||||
| describe('Renote Mute', () => { | ||||
| @@ -35,7 +36,7 @@ describe('Renote Mute', () => { | ||||
| 		const carolNote = await post(carol, { text: 'hi' }); | ||||
|  | ||||
| 		// redisに追加されるのを待つ | ||||
| 		await sleep(100); | ||||
| 		await setTimeout(100); | ||||
|  | ||||
| 		const res = await api('notes/local-timeline', {}, alice); | ||||
|  | ||||
| @@ -52,7 +53,7 @@ describe('Renote Mute', () => { | ||||
| 		const carolNote = await post(carol, { text: 'hi' }); | ||||
|  | ||||
| 		// redisに追加されるのを待つ | ||||
| 		await sleep(100); | ||||
| 		await setTimeout(100); | ||||
|  | ||||
| 		const res = await api('notes/local-timeline', {}, alice); | ||||
|  | ||||
| @@ -69,7 +70,7 @@ describe('Renote Mute', () => { | ||||
| 		const bobRenote = await post(bob, { renoteId: carolNote.id }); | ||||
|  | ||||
| 		// redisに追加されるのを待つ | ||||
| 		await sleep(100); | ||||
| 		await setTimeout(100); | ||||
|  | ||||
| 		const res = await api('notes/local-timeline', {}, alice); | ||||
|  | ||||
|   | ||||
| @@ -7,16 +7,17 @@ | ||||
| // pnpm jest -- e2e/timelines.ts | ||||
|  | ||||
| import * as assert from 'assert'; | ||||
| import { setTimeout } from 'node:timers/promises'; | ||||
| import { Redis } from 'ioredis'; | ||||
| import { loadConfig } from '@/config.js'; | ||||
| import { api, post, randomString, sendEnvUpdateRequest, signup, sleep, uploadUrl } from '../utils.js'; | ||||
| import { api, post, randomString, sendEnvUpdateRequest, signup, uploadUrl } from '../utils.js'; | ||||
|  | ||||
| function genHost() { | ||||
| 	return randomString() + '.example.com'; | ||||
| } | ||||
|  | ||||
| function waitForPushToTl() { | ||||
| 	return sleep(500); | ||||
| 	return setTimeout(500); | ||||
| } | ||||
|  | ||||
| let redisForTimelines: Redis; | ||||
| @@ -44,7 +45,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi' }); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
|  | ||||
| @@ -60,7 +61,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
|  | ||||
| @@ -77,7 +78,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); | ||||
|  | ||||
| @@ -94,7 +95,7 @@ describe('Timelines', () => { | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await api('following/update', { userId: bob.id, withReplies: true }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); | ||||
|  | ||||
| @@ -111,7 +112,7 @@ describe('Timelines', () => { | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await api('following/update', { userId: bob.id, withReplies: true }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id, visibility: 'specified', visibleUserIds: [carolNote.id] }); | ||||
|  | ||||
| @@ -128,7 +129,7 @@ describe('Timelines', () => { | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await api('following/update', { userId: bob.id, withReplies: true }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi', visibility: 'followers' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); | ||||
|  | ||||
| @@ -147,7 +148,7 @@ describe('Timelines', () => { | ||||
| 			await api('following/create', { userId: carol.id }, alice); | ||||
| 			await api('following/create', { userId: carol.id }, bob); | ||||
| 			await api('following/update', { userId: bob.id, withReplies: true }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi', visibility: 'followers' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); | ||||
|  | ||||
| @@ -166,7 +167,7 @@ describe('Timelines', () => { | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await api('following/create', { userId: carol.id }, alice); | ||||
| 			await api('following/update', { userId: bob.id, withReplies: true }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id, visibility: 'specified', visibleUserIds: [carolNote.id] }); | ||||
|  | ||||
| @@ -182,7 +183,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob] = await Promise.all([signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote1 = await post(bob, { text: 'hi' }); | ||||
| 			const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id }); | ||||
|  | ||||
| @@ -198,7 +199,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob] = await Promise.all([signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const aliceNote = await post(alice, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id }); | ||||
|  | ||||
| @@ -228,7 +229,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { renoteId: carolNote.id }); | ||||
|  | ||||
| @@ -244,7 +245,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { renoteId: carolNote.id }); | ||||
|  | ||||
| @@ -262,7 +263,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); | ||||
|  | ||||
| @@ -280,7 +281,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] }); | ||||
|  | ||||
| 			await waitForPushToTl(); | ||||
| @@ -295,7 +296,7 @@ describe('Timelines', () => { | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await api('mute/create', { userId: carol.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); | ||||
|  | ||||
| @@ -313,7 +314,7 @@ describe('Timelines', () => { | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await api('following/update', { userId: bob.id, withReplies: true }, alice); | ||||
| 			await api('mute/create', { userId: carol.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); | ||||
|  | ||||
| @@ -359,7 +360,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const [bobFile, carolFile] = await Promise.all([ | ||||
| 				uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'), | ||||
| 				uploadUrl(carol, 'https://raw.githubusercontent.com/misskey-dev/assets/main/public/icon.png'), | ||||
| @@ -384,7 +385,7 @@ describe('Timelines', () => { | ||||
|  | ||||
| 			const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body); | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi', channelId: channel.id }); | ||||
|  | ||||
| 			await waitForPushToTl(); | ||||
| @@ -411,7 +412,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob] = await Promise.all([signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [alice.id] }); | ||||
|  | ||||
| 			await waitForPushToTl(); | ||||
| @@ -438,7 +439,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] }); | ||||
|  | ||||
| 			await waitForPushToTl(); | ||||
| @@ -566,7 +567,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: carol.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi', visibility: 'home' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi' }); | ||||
|  | ||||
| @@ -582,7 +583,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); | ||||
|  | ||||
| 			await api('mute/create', { userId: carol.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi' }); | ||||
|  | ||||
| @@ -599,7 +600,7 @@ describe('Timelines', () => { | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await api('mute/create', { userId: carol.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); | ||||
|  | ||||
| @@ -617,7 +618,7 @@ describe('Timelines', () => { | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await api('following/update', { userId: bob.id, withReplies: true }, alice); | ||||
| 			await api('mute/create', { userId: carol.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); | ||||
|  | ||||
| @@ -633,7 +634,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob] = await Promise.all([signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const aliceNote = await post(alice, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id }); | ||||
|  | ||||
| @@ -703,7 +704,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob] = await Promise.all([signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); | ||||
|  | ||||
| 			await waitForPushToTl(); | ||||
| @@ -717,7 +718,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob] = await Promise.all([signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const aliceNote = await post(alice, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id }); | ||||
|  | ||||
| @@ -820,7 +821,7 @@ describe('Timelines', () => { | ||||
|  | ||||
| 			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); | ||||
| 			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi' }); | ||||
|  | ||||
| 			await waitForPushToTl(); | ||||
| @@ -835,7 +836,7 @@ describe('Timelines', () => { | ||||
|  | ||||
| 			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); | ||||
| 			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); | ||||
|  | ||||
| 			await waitForPushToTl(); | ||||
| @@ -850,7 +851,7 @@ describe('Timelines', () => { | ||||
|  | ||||
| 			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); | ||||
| 			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); | ||||
|  | ||||
| 			await waitForPushToTl(); | ||||
| @@ -865,7 +866,7 @@ describe('Timelines', () => { | ||||
|  | ||||
| 			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); | ||||
| 			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); | ||||
|  | ||||
| @@ -881,7 +882,7 @@ describe('Timelines', () => { | ||||
|  | ||||
| 			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); | ||||
| 			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote1 = await post(bob, { text: 'hi' }); | ||||
| 			const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id }); | ||||
|  | ||||
| @@ -899,7 +900,7 @@ describe('Timelines', () => { | ||||
| 			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); | ||||
| 			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); | ||||
| 			await api('users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: false }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const aliceNote = await post(alice, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', replyId: aliceNote.id }); | ||||
|  | ||||
| @@ -916,7 +917,7 @@ describe('Timelines', () => { | ||||
| 			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); | ||||
| 			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); | ||||
| 			await api('users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: false }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); | ||||
|  | ||||
| @@ -933,7 +934,7 @@ describe('Timelines', () => { | ||||
| 			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); | ||||
| 			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); | ||||
| 			await api('users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: true }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); | ||||
|  | ||||
| @@ -950,7 +951,7 @@ describe('Timelines', () => { | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); | ||||
| 			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); | ||||
|  | ||||
| 			await waitForPushToTl(); | ||||
| @@ -966,7 +967,7 @@ describe('Timelines', () => { | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); | ||||
| 			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); | ||||
|  | ||||
| 			await waitForPushToTl(); | ||||
| @@ -982,7 +983,7 @@ describe('Timelines', () => { | ||||
|  | ||||
| 			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); | ||||
| 			await api('users/lists/push', { listId: list.id, userId: alice.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const aliceNote = await post(alice, { text: 'hi', visibility: 'followers' }); | ||||
|  | ||||
| 			await waitForPushToTl(); | ||||
| @@ -999,7 +1000,7 @@ describe('Timelines', () => { | ||||
| 			const channel = await api('channels/create', { name: 'channel' }, bob).then(x => x.body); | ||||
| 			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); | ||||
| 			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi', channelId: channel.id }); | ||||
|  | ||||
| 			await waitForPushToTl(); | ||||
| @@ -1031,7 +1032,7 @@ describe('Timelines', () => { | ||||
|  | ||||
| 			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); | ||||
| 			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [alice.id] }); | ||||
|  | ||||
| 			await waitForPushToTl(); | ||||
| @@ -1048,7 +1049,7 @@ describe('Timelines', () => { | ||||
| 			const list = await api('users/lists/create', { name: 'list' }, alice).then(res => res.body); | ||||
| 			await api('users/lists/push', { listId: list.id, userId: bob.id }, alice); | ||||
| 			await api('users/lists/push', { listId: list.id, userId: carol.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] }); | ||||
|  | ||||
| 			await waitForPushToTl(); | ||||
| @@ -1088,7 +1089,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob] = await Promise.all([signup(), signup()]); | ||||
|  | ||||
| 			await api('following/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); | ||||
|  | ||||
| 			await waitForPushToTl(); | ||||
| @@ -1228,7 +1229,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); | ||||
|  | ||||
| 			await api('mute/create', { userId: carol.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const carolNote = await post(carol, { text: 'hi' }); | ||||
| 			const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); | ||||
|  | ||||
| @@ -1243,7 +1244,7 @@ describe('Timelines', () => { | ||||
| 			const [alice, bob] = await Promise.all([signup(), signup()]); | ||||
|  | ||||
| 			await api('mute/create', { userId: bob.id }, alice); | ||||
| 			await sleep(1000); | ||||
| 			await setTimeout(1000); | ||||
| 			const bobNote1 = await post(bob, { text: 'hi' }); | ||||
| 			const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id }); | ||||
| 			const bobNote3 = await post(bob, { text: 'hi', renoteId: bobNote1.id }); | ||||
|   | ||||
| @@ -17,8 +17,8 @@ describe('users/notes', () => { | ||||
|  | ||||
| 	beforeAll(async () => { | ||||
| 		alice = await signup({ username: 'alice' }); | ||||
| 		const jpg = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.jpg'); | ||||
| 		const png = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/Lenna.png'); | ||||
| 		const jpg = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.jpg'); | ||||
| 		const png = await uploadUrl(alice, 'https://raw.githubusercontent.com/misskey-dev/misskey/develop/packages/backend/test/resources/192.png'); | ||||
| 		jpgNote = await post(alice, { | ||||
| 			fileIds: [jpg.id], | ||||
| 		}); | ||||
|   | ||||
							
								
								
									
										22
									
								
								packages/backend/test/eslint.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								packages/backend/test/eslint.config.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| import globals from 'globals'; | ||||
| import tsParser from '@typescript-eslint/parser'; | ||||
| import sharedConfig from '../../shared/eslint.config.js'; | ||||
|  | ||||
| export default [ | ||||
| 	...sharedConfig, | ||||
| 	{ | ||||
| 		files: ['**/*.ts', '**/*.tsx'], | ||||
| 		languageOptions: { | ||||
| 			globals: { | ||||
| 				...globals.node, | ||||
| 				...globals.jest, | ||||
| 			}, | ||||
| 			parserOptions: { | ||||
| 				parser: tsParser, | ||||
| 				project: ['./tsconfig.json'], | ||||
| 				sourceType: 'module', | ||||
| 				tsconfigRootDir: import.meta.dirname, | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, | ||||
| ]; | ||||
							
								
								
									
										
											BIN
										
									
								
								packages/backend/test/resources/192.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								packages/backend/test/resources/192.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 5.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								packages/backend/test/resources/192.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								packages/backend/test/resources/192.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 26 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 25 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 463 KiB | 
| @@ -83,21 +83,21 @@ describe('FileInfoService', () => { | ||||
|  | ||||
| 	describe('IMAGE', () => { | ||||
| 		test('Generic JPEG', async () => { | ||||
| 			const path = `${resources}/Lenna.jpg`; | ||||
| 			const path = `${resources}/192.jpg`; | ||||
| 			const info = await fileInfoService.getFileInfo(path, { skipSensitiveDetection: true }) as any; | ||||
| 			delete info.warnings; | ||||
| 			delete info.blurhash; | ||||
| 			delete info.sensitive; | ||||
| 			delete info.porn; | ||||
| 			assert.deepStrictEqual(info, { | ||||
| 				size: 25360, | ||||
| 				md5: '091b3f259662aa31e2ffef4519951168', | ||||
| 				size: 5131, | ||||
| 				md5: '8c9ed0677dd2b8f9f7472c3af247e5e3', | ||||
| 				type: { | ||||
| 					mime: 'image/jpeg', | ||||
| 					ext: 'jpg', | ||||
| 				}, | ||||
| 				width: 512, | ||||
| 				height: 512, | ||||
| 				width: 192, | ||||
| 				height: 192, | ||||
| 				orientation: undefined, | ||||
| 			}); | ||||
| 		}); | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
|  | ||||
| process.env.NODE_ENV = 'test'; | ||||
|  | ||||
| import { setTimeout } from 'node:timers/promises'; | ||||
| import { jest } from '@jest/globals'; | ||||
| import { ModuleMocker } from 'jest-mock'; | ||||
| import { Test } from '@nestjs/testing'; | ||||
| @@ -29,7 +30,6 @@ import { secureRndstr } from '@/misc/secure-rndstr.js'; | ||||
| import { NotificationService } from '@/core/NotificationService.js'; | ||||
| import { RoleCondFormulaValue } from '@/models/Role.js'; | ||||
| import { UserEntityService } from '@/core/entities/UserEntityService.js'; | ||||
| import { sleep } from '../utils.js'; | ||||
| import type { TestingModule } from '@nestjs/testing'; | ||||
| import type { MockFunctionMetadata } from 'jest-mock'; | ||||
|  | ||||
| @@ -278,7 +278,7 @@ describe('RoleService', () => { | ||||
|  | ||||
| 			// ストリーミング経由で反映されるまでちょっと待つ | ||||
| 			clock.uninstall(); | ||||
| 			await sleep(100); | ||||
| 			await setTimeout(100); | ||||
|  | ||||
| 			const resultAfter25hAgain = await roleService.getUserPolicies(user.id); | ||||
| 			expect(resultAfter25hAgain.canManageCustomEmojis).toBe(true); | ||||
| @@ -807,7 +807,7 @@ describe('RoleService', () => { | ||||
| 			await roleService.assign(user.id, role.id); | ||||
|  | ||||
| 			clock.uninstall(); | ||||
| 			await sleep(100); | ||||
| 			await setTimeout(100); | ||||
|  | ||||
| 			const assignments = await roleAssignmentsRepository.find({ | ||||
| 				where: { | ||||
| @@ -835,7 +835,7 @@ describe('RoleService', () => { | ||||
| 			await roleService.assign(user.id, role.id); | ||||
|  | ||||
| 			clock.uninstall(); | ||||
| 			await sleep(100); | ||||
| 			await setTimeout(100); | ||||
|  | ||||
| 			const assignments = await roleAssignmentsRepository.find({ | ||||
| 				where: { | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
|  * SPDX-License-Identifier: AGPL-3.0-only | ||||
|  */ | ||||
|  | ||||
| import { setTimeout } from 'node:timers/promises'; | ||||
| import { afterEach, beforeEach, describe, expect, jest } from '@jest/globals'; | ||||
| import { Test, TestingModule } from '@nestjs/testing'; | ||||
| import { MiUser } from '@/models/User.js'; | ||||
| @@ -16,7 +17,7 @@ import { DI } from '@/di-symbols.js'; | ||||
| import { QueueService } from '@/core/QueueService.js'; | ||||
| import { LoggerService } from '@/core/LoggerService.js'; | ||||
| import { SystemWebhookService } from '@/core/SystemWebhookService.js'; | ||||
| import { randomString, sleep } from '../utils.js'; | ||||
| import { randomString } from '../utils.js'; | ||||
|  | ||||
| describe('SystemWebhookService', () => { | ||||
| 	let app: TestingModule; | ||||
| @@ -358,7 +359,7 @@ describe('SystemWebhookService', () => { | ||||
| 					); | ||||
|  | ||||
| 					// redisでの配信経由で更新されるのでちょっと待つ | ||||
| 					await sleep(500); | ||||
| 					await setTimeout(500); | ||||
|  | ||||
| 					const fetchedWebhooks = await service.fetchActiveSystemWebhooks(); | ||||
| 					expect(fetchedWebhooks).toEqual([webhook]); | ||||
| @@ -377,7 +378,7 @@ describe('SystemWebhookService', () => { | ||||
| 					); | ||||
|  | ||||
| 					// redisでの配信経由で更新されるのでちょっと待つ | ||||
| 					await sleep(500); | ||||
| 					await setTimeout(500); | ||||
|  | ||||
| 					const fetchedWebhooks = await service.fetchActiveSystemWebhooks(); | ||||
| 					expect(fetchedWebhooks).toEqual([]); | ||||
| @@ -407,7 +408,7 @@ describe('SystemWebhookService', () => { | ||||
| 					); | ||||
|  | ||||
| 					// redisでの配信経由で更新されるのでちょっと待つ | ||||
| 					await sleep(500); | ||||
| 					await setTimeout(500); | ||||
|  | ||||
| 					const fetchedWebhooks = await service.fetchActiveSystemWebhooks(); | ||||
| 					expect(fetchedWebhooks).toEqual([webhook2]); | ||||
| @@ -434,7 +435,7 @@ describe('SystemWebhookService', () => { | ||||
| 					); | ||||
|  | ||||
| 					// redisでの配信経由で更新されるのでちょっと待つ | ||||
| 					await sleep(500); | ||||
| 					await setTimeout(500); | ||||
|  | ||||
| 					const fetchedWebhooks = await service.fetchActiveSystemWebhooks(); | ||||
| 					expect(fetchedWebhooks.length).toEqual(0); | ||||
| @@ -457,7 +458,7 @@ describe('SystemWebhookService', () => { | ||||
| 					); | ||||
|  | ||||
| 					// redisでの配信経由で更新されるのでちょっと待つ | ||||
| 					await sleep(500); | ||||
| 					await setTimeout(500); | ||||
|  | ||||
| 					const fetchedWebhooks = await service.fetchActiveSystemWebhooks(); | ||||
| 					expect(fetchedWebhooks).toEqual([webhook2]); | ||||
| @@ -481,7 +482,7 @@ describe('SystemWebhookService', () => { | ||||
| 					); | ||||
|  | ||||
| 					// redisでの配信経由で更新されるのでちょっと待つ | ||||
| 					await sleep(500); | ||||
| 					await setTimeout(500); | ||||
|  | ||||
| 					const fetchedWebhooks = await service.fetchActiveSystemWebhooks(); | ||||
| 					expect(fetchedWebhooks.length).toEqual(0); | ||||
| @@ -504,7 +505,7 @@ describe('SystemWebhookService', () => { | ||||
| 					); | ||||
|  | ||||
| 					// redisでの配信経由で更新されるのでちょっと待つ | ||||
| 					await sleep(500); | ||||
| 					await setTimeout(500); | ||||
|  | ||||
| 					const fetchedWebhooks = await service.fetchActiveSystemWebhooks(); | ||||
| 					expect(fetchedWebhooks.length).toEqual(0); | ||||
|   | ||||
| @@ -297,7 +297,7 @@ export const uploadFile = async (user?: UserToken, { path, name, blob }: UploadO | ||||
| 	body: misskey.entities.DriveFile | null | ||||
| }> => { | ||||
| 	const absPath = path == null | ||||
| 		? new URL('resources/Lenna.jpg', import.meta.url) | ||||
| 		? new URL('resources/192.jpg', import.meta.url) | ||||
| 		: isAbsolute(path.toString()) | ||||
| 			? new URL(path) | ||||
| 			: new URL(path, new URL('resources/', import.meta.url)); | ||||
| @@ -605,14 +605,6 @@ export async function initTestDb(justBorrow = false, initEntities?: any[]) { | ||||
| 	return db; | ||||
| } | ||||
|  | ||||
| export function sleep(msec: number) { | ||||
| 	return new Promise<void>(res => { | ||||
| 		setTimeout(() => { | ||||
| 			res(); | ||||
| 		}, msec); | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| export async function sendEnvUpdateRequest(params: { key: string, value?: string }) { | ||||
| 	const res = await fetch( | ||||
| 		`http://localhost:${port + 1000}/env`, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 syuilo
					syuilo