mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
chore(deps): upgrade all dependencies, toolchains and images (#2825)
This commit is contained in:
@@ -9,12 +9,12 @@
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"typecheck": "tsgo --noEmit"
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"@vitest/coverage-v8": "catalog:",
|
||||
"typescript": "catalog:ts7",
|
||||
"vitest": "catalog:",
|
||||
"yaml": "catalog:"
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"typecheck": "tsgo --noEmit"
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"typescript": "catalog:ts7",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfigs/package.json",
|
||||
"compilerOptions": {},
|
||||
"compilerOptions": {
|
||||
"types": []
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"./*": "./*"
|
||||
},
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit"
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluxer/constants": "workspace:*",
|
||||
@@ -15,6 +15,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:"
|
||||
"typescript": "catalog:ts7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
{
|
||||
"extends": "../../tsconfigs/package.json",
|
||||
"compilerOptions": {
|
||||
"types": ["node"]
|
||||
},
|
||||
"compilerOptions": {},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"typecheck": "tsgo --noEmit"
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluxer/config": "workspace:*",
|
||||
@@ -23,7 +23,7 @@
|
||||
"devDependencies": {
|
||||
"@messageformat/parser": "catalog:",
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"typescript": "catalog:ts7",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,26 +51,24 @@ describe('AppErrorHandler i18n fallbacks', () => {
|
||||
requestId: undefined,
|
||||
message: 'Internal server error.',
|
||||
},
|
||||
])('$name and logs unexpected errors with request metadata', async ({
|
||||
acceptLanguage,
|
||||
requestLocale,
|
||||
requestId,
|
||||
message,
|
||||
}) => {
|
||||
const errorLogger = vi.spyOn(Logger.prototype, 'error').mockImplementation(() => {});
|
||||
const error = new Error('Private internal failure');
|
||||
const headers = new Headers();
|
||||
if (acceptLanguage !== undefined) {
|
||||
headers.set('accept-language', acceptLanguage);
|
||||
}
|
||||
const response = await createApp(error, requestLocale, requestId).request('/test', {headers});
|
||||
expect(response.status).toBe(500);
|
||||
expect(await response.json()).toEqual({code: APIErrorCodes.INTERNAL_SERVER_ERROR, message});
|
||||
expect(errorLogger).toHaveBeenCalledExactlyOnceWith(
|
||||
{err: error, status: 500, method: 'GET', path: '/test', requestId},
|
||||
'Unhandled error occurred',
|
||||
);
|
||||
});
|
||||
])(
|
||||
'$name and logs unexpected errors with request metadata',
|
||||
async ({acceptLanguage, requestLocale, requestId, message}) => {
|
||||
const errorLogger = vi.spyOn(Logger.prototype, 'error').mockImplementation(() => {});
|
||||
const error = new Error('Private internal failure');
|
||||
const headers = new Headers();
|
||||
if (acceptLanguage !== undefined) {
|
||||
headers.set('accept-language', acceptLanguage);
|
||||
}
|
||||
const response = await createApp(error, requestLocale, requestId).request('/test', {headers});
|
||||
expect(response.status).toBe(500);
|
||||
expect(await response.json()).toEqual({code: APIErrorCodes.INTERNAL_SERVER_ERROR, message});
|
||||
expect(errorLogger).toHaveBeenCalledExactlyOnceWith(
|
||||
{err: error, status: 500, method: 'GET', path: '/test', requestId},
|
||||
'Unhandled error occurred',
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
it('localizes FluxerError responses without an i18n service and logs them as expected rejections', async () => {
|
||||
const errorLogger = vi.spyOn(Logger.prototype, 'error').mockImplementation(() => {});
|
||||
|
||||
@@ -53,15 +53,14 @@ describe.each([
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
BadRequestError,
|
||||
ForbiddenError,
|
||||
NotFoundError,
|
||||
])('preserves custom messages for client errors', (ErrorClass) => {
|
||||
const error = new ErrorClass({code: APIErrorCodes.INVALID_REQUEST, message: 'Custom error message'});
|
||||
it.each([BadRequestError, ForbiddenError, NotFoundError])(
|
||||
'preserves custom messages for client errors',
|
||||
(ErrorClass) => {
|
||||
const error = new ErrorClass({code: APIErrorCodes.INVALID_REQUEST, message: 'Custom error message'});
|
||||
|
||||
expect(error.toJSON()).toEqual({code: APIErrorCodes.INVALID_REQUEST, message: 'Custom error message'});
|
||||
});
|
||||
expect(error.toJSON()).toEqual({code: APIErrorCodes.INVALID_REQUEST, message: 'Custom error message'});
|
||||
},
|
||||
);
|
||||
|
||||
describe.each([
|
||||
[APIErrorCodes.INVALID_PHONE_NUMBER, InvalidPhoneNumberError, BadRequestError, HttpStatus.BAD_REQUEST],
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
"./*": "./*"
|
||||
},
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit"
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluxer/constants": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:"
|
||||
"typescript": "catalog:ts7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"typecheck": "tsgo --noEmit"
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluxer/constants": "workspace:*",
|
||||
@@ -19,7 +19,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"typescript": "catalog:ts7",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit"
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript/native-preview": "catalog:"
|
||||
"typescript": "catalog:ts7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfigs/package.json",
|
||||
"compilerOptions": {},
|
||||
"compilerOptions": {
|
||||
"types": []
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"static:sync": "tsx scripts/SyncStaticI18nCatalogs.ts --extract --compile",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"typecheck": "tsgo --noEmit"
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@messageformat/core": "catalog:",
|
||||
@@ -24,8 +24,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"tsx": "catalog:",
|
||||
"typescript": "catalog:ts7",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfigs/base.json",
|
||||
"compilerOptions": {
|
||||
"types": ["node"],
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"./*": "./*"
|
||||
},
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit"
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluxer/constants": "workspace:*",
|
||||
@@ -17,6 +17,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:"
|
||||
"typescript": "catalog:ts7"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"typecheck": "tsgo --noEmit"
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"@vitest/coverage-v8": "catalog:",
|
||||
"typescript": "catalog:ts7",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
"./*": "./*"
|
||||
},
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluxer/constants": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"typescript": "catalog:ts7",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfigs/package.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src"
|
||||
"types": []
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"typecheck": "tsgo --noEmit"
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"pino": "catalog:",
|
||||
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"typescript": "catalog:ts7",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
+36
-52
@@ -10,9 +10,9 @@ checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.63"
|
||||
version = "1.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f"
|
||||
checksum = "a3eb0f42d6c360dc3f8a821f6bf2fdea7f72bfd36b3076eb0e6d1e9e0752fff4"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
@@ -22,15 +22,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.9"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||
checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d"
|
||||
|
||||
[[package]]
|
||||
name = "fluxer_markdown_parser"
|
||||
@@ -51,14 +51,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.4"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||
checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasip2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -69,9 +68,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.34"
|
||||
version = "0.1.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
||||
checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libc",
|
||||
@@ -79,15 +78,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.186"
|
||||
version = "0.2.189"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
version = "0.4.12"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d"
|
||||
checksum = "a9fd2f41a1cba099f79a0b6b6c35656cf7c03351a7bae8ff0f28f25270f929d2"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"cc",
|
||||
@@ -95,39 +94,39 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.1"
|
||||
version = "2.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
|
||||
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.3.0"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
@@ -135,18 +134,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -155,9 +154,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.150"
|
||||
version = "1.0.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
||||
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
@@ -174,9 +173,9 @@ checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -185,27 +184,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "wasip2"
|
||||
version = "1.0.3+wasi-0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.57.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
||||
checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.21"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"scripts": {
|
||||
"generate": "tsx src/scripts/GenerateSpec.ts",
|
||||
"test": "vitest run",
|
||||
"typecheck": "tsgo --noEmit",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"validate": "tsx src/scripts/GenerateSpec.ts --validate-only"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -22,8 +22,8 @@
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "catalog:",
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"tsx": "catalog:",
|
||||
"typescript": "catalog:ts7",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ describe('native Zod conversion', () => {
|
||||
expect(input.required).toEqual(['note']);
|
||||
expect(output.required).toEqual(['name', 'note']);
|
||||
expect(input.properties?.name).toMatchObject({type: 'string', default: 'guest'});
|
||||
expect(input.properties?.note).toEqual({anyOf: [{type: 'string'}, {type: 'null'}]});
|
||||
expect(input.properties?.note).toEqual({type: ['string', 'null']});
|
||||
expect(input.additionalProperties).toBeUndefined();
|
||||
expect(output.additionalProperties).toBe(false);
|
||||
const document = documentFor(converter);
|
||||
|
||||
@@ -53,17 +53,17 @@ describe('discoverControllerFiles', () => {
|
||||
const route = routes.find((route) => route.path === '/donations/manage');
|
||||
expect(route?.explicitSecurity).toEqual([]);
|
||||
});
|
||||
it.each([
|
||||
'download_latest_desktop_version_checksum',
|
||||
'download_desktop_version_checksum',
|
||||
])('preserves the plain-text checksum response for %s', (operationId) => {
|
||||
const route = routes.find((route) => route.explicitOperationId === operationId);
|
||||
expect(route).toMatchObject({
|
||||
responseSchemaName: 'DownloadChecksumResponse',
|
||||
responseContentType: 'text/plain',
|
||||
explicitStatusCodes: [200],
|
||||
});
|
||||
});
|
||||
it.each(['download_latest_desktop_version_checksum', 'download_desktop_version_checksum'])(
|
||||
'preserves the plain-text checksum response for %s',
|
||||
(operationId) => {
|
||||
const route = routes.find((route) => route.explicitOperationId === operationId);
|
||||
expect(route).toMatchObject({
|
||||
responseSchemaName: 'DownloadChecksumResponse',
|
||||
responseContentType: 'text/plain',
|
||||
explicitStatusCodes: [200],
|
||||
});
|
||||
},
|
||||
);
|
||||
it('rejects a bodyless status that is absent from the route response statuses', () => {
|
||||
const route = routes.find((route) => route.path === '/donations/manage');
|
||||
assert(route);
|
||||
|
||||
@@ -19,19 +19,12 @@ describe('static route expressions', () => {
|
||||
expect(resolveExpression(`paths[${JSON.stringify(index)}]`)).toBe(Number(index) === 0 ? '/first' : '/second');
|
||||
});
|
||||
|
||||
it.each([
|
||||
'1suffix',
|
||||
'1.5',
|
||||
'01',
|
||||
'1e0',
|
||||
' 1',
|
||||
'',
|
||||
'-0',
|
||||
-1,
|
||||
2,
|
||||
])('does not coerce array property %j into a route index', (index) => {
|
||||
expect(resolveExpression(`paths[${JSON.stringify(index)}]`)).toBe(UNRESOLVED);
|
||||
});
|
||||
it.each(['1suffix', '1.5', '01', '1e0', ' 1', '', '-0', -1, 2])(
|
||||
'does not coerce array property %j into a route index',
|
||||
(index) => {
|
||||
expect(resolveExpression(`paths[${JSON.stringify(index)}]`)).toBe(UNRESOLVED);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('imported route constants', () => {
|
||||
|
||||
@@ -142,7 +142,7 @@ export class OpenAPIOperationBuilder {
|
||||
const location = validator.target === 'param' ? 'path' : validator.target;
|
||||
const schemaName = validator.schemaName;
|
||||
const schema = this.schemaRegistry.get(schemaName);
|
||||
if (!schema || schema.type !== 'object' || !schema.properties) {
|
||||
if (schema?.type !== 'object' || !schema.properties) {
|
||||
throw new Error(`Parameter schema must be an object: ${schemaName}`);
|
||||
}
|
||||
const required = new Set(schema.required ?? []);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"extends": "../../tsconfigs/base.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext"],
|
||||
"types": ["node"],
|
||||
"paths": {
|
||||
"@fluxer/*": ["./../../packages/*"]
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
"test": "vitest run",
|
||||
"test:coverage": "vitest run --coverage",
|
||||
"test:watch": "vitest",
|
||||
"typecheck": "tsgo --noEmit",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"generate": "cd proto && buf generate && ../../../tools/ci/run.sh clean-schema-generated-files --root ../src/gen && cd .. && pnpm exec biome check --write --unsafe --no-errors-on-unmatched src/gen"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bufbuild/protobuf": "^2.12.0",
|
||||
"@bufbuild/protobuf": "^2.15.0",
|
||||
"@fluxer/constants": "workspace:*",
|
||||
"@simplewebauthn/server": "catalog:",
|
||||
"emoji-regex": "catalog:",
|
||||
@@ -23,11 +23,11 @@
|
||||
"zod": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@bufbuild/buf": "^1.69.0",
|
||||
"@bufbuild/protoc-gen-es": "^2.12.0",
|
||||
"@bufbuild/buf": "^1.73.0",
|
||||
"@bufbuild/protoc-gen-es": "^2.15.0",
|
||||
"@types/node": "catalog:",
|
||||
"@types/validator": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"typescript": "catalog:ts7",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,14 +31,12 @@ describe('voice noise suppression configuration', () => {
|
||||
expect(second).toEqual(DEFAULT_VOICE_NOISE_SUPPRESSION_CONFIG);
|
||||
});
|
||||
|
||||
test.each([
|
||||
{},
|
||||
{enabled: false},
|
||||
{enabled: undefined},
|
||||
{suppression_strength: 42},
|
||||
])('keeps partial updates free of configuration defaults: %j', (patch) => {
|
||||
expect(VoiceNoiseSuppressionConfigUpdateRequest.parse(patch)).toEqual(patch);
|
||||
});
|
||||
test.each([{}, {enabled: false}, {enabled: undefined}, {suppression_strength: 42}])(
|
||||
'keeps partial updates free of configuration defaults: %j',
|
||||
(patch) => {
|
||||
expect(VoiceNoiseSuppressionConfigUpdateRequest.parse(patch)).toEqual(patch);
|
||||
},
|
||||
);
|
||||
|
||||
test('does not accept a client-provided configuration version', () => {
|
||||
expect(VoiceNoiseSuppressionConfigUpdateRequest.parse({config_version: 12})).toEqual({});
|
||||
@@ -371,23 +369,21 @@ describe('resolveVoiceNoiseSuppressionForCall', () => {
|
||||
{allowUserOverride: true, preference: 'gtcrn', expectedBackend: 'rnnoise', expectedSource: 'canary'},
|
||||
{allowUserOverride: false, preference: 'speex', expectedBackend: 'rnnoise', expectedSource: 'canary'},
|
||||
{allowUserOverride: true, preference: null, expectedBackend: 'rnnoise', expectedSource: 'canary'},
|
||||
] as const)('allow_user_override $allowUserOverride with preference $preference resolves to $expectedSource', ({
|
||||
allowUserOverride,
|
||||
preference,
|
||||
expectedBackend,
|
||||
expectedSource,
|
||||
}) => {
|
||||
const assignment = createAssignment({
|
||||
backend: 'rnnoise',
|
||||
source: 'canary',
|
||||
allow_user_override: allowUserOverride,
|
||||
enabled_backends: ['none', 'standard', 'speex', 'rnnoise'],
|
||||
});
|
||||
expect(resolveVoiceNoiseSuppressionForCall(assignment, null, preference)).toMatchObject({
|
||||
backend: expectedBackend,
|
||||
source: expectedSource,
|
||||
});
|
||||
});
|
||||
] as const)(
|
||||
'allow_user_override $allowUserOverride with preference $preference resolves to $expectedSource',
|
||||
({allowUserOverride, preference, expectedBackend, expectedSource}) => {
|
||||
const assignment = createAssignment({
|
||||
backend: 'rnnoise',
|
||||
source: 'canary',
|
||||
allow_user_override: allowUserOverride,
|
||||
enabled_backends: ['none', 'standard', 'speex', 'rnnoise'],
|
||||
});
|
||||
expect(resolveVoiceNoiseSuppressionForCall(assignment, null, preference)).toMatchObject({
|
||||
backend: expectedBackend,
|
||||
source: expectedSource,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test('a user override also outranks a guild rule', () => {
|
||||
const assignment = createAssignment({
|
||||
|
||||
@@ -96,20 +96,17 @@ describe('TemplateChannel permission overwrites', () => {
|
||||
expect(channel.permission_overwrites).toEqual([{id: '2', type: expected, allow: '8', deny: '0'}]);
|
||||
});
|
||||
|
||||
it.each([
|
||||
'invalid',
|
||||
'NaN',
|
||||
'Infinity',
|
||||
Number.NaN,
|
||||
Number.POSITIVE_INFINITY,
|
||||
])('rejects nonfinite overwrite type %j', (type) => {
|
||||
expect(
|
||||
TemplateChannel.safeParse({
|
||||
id: '1',
|
||||
type: 0,
|
||||
position: 0,
|
||||
permission_overwrites: [{id: '2', type, allow: '8', deny: '0'}],
|
||||
}).success,
|
||||
).toBe(false);
|
||||
});
|
||||
it.each(['invalid', 'NaN', 'Infinity', Number.NaN, Number.POSITIVE_INFINITY])(
|
||||
'rejects nonfinite overwrite type %j',
|
||||
(type) => {
|
||||
expect(
|
||||
TemplateChannel.safeParse({
|
||||
id: '1',
|
||||
type: 0,
|
||||
position: 0,
|
||||
permission_overwrites: [{id: '2', type, allow: '8', deny: '0'}],
|
||||
}).success,
|
||||
).toBe(false);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -10,17 +10,14 @@ describe('jobs schemas', () => {
|
||||
expect(JobLedgerEntrySchema.shape.status.safeParse('failed').success).toBe(false);
|
||||
});
|
||||
|
||||
test.each([
|
||||
'queued',
|
||||
'running',
|
||||
'succeeded',
|
||||
'cancelled',
|
||||
'deadletter',
|
||||
])('accepts ledger status %s across query, request, and response', (status) => {
|
||||
expect(ListJobsQuery.parse({status}).status).toBe(status);
|
||||
expect(ListJobsRequest.parse({status}).status).toBe(status);
|
||||
expect(JobLedgerEntrySchema.shape.status.parse(status)).toBe(status);
|
||||
});
|
||||
test.each(['queued', 'running', 'succeeded', 'cancelled', 'deadletter'])(
|
||||
'accepts ledger status %s across query, request, and response',
|
||||
(status) => {
|
||||
expect(ListJobsQuery.parse({status}).status).toBe(status);
|
||||
expect(ListJobsRequest.parse({status}).status).toBe(status);
|
||||
expect(JobLedgerEntrySchema.shape.status.parse(status)).toBe(status);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('job pagination cursor', () => {
|
||||
@@ -34,16 +31,15 @@ describe('job pagination cursor', () => {
|
||||
expect(ListJobsQuery.parse(cursor)).toEqual({...cursor, limit: 50, max_lookback_days: 14});
|
||||
});
|
||||
|
||||
test.each([
|
||||
'cursor_bucket_day',
|
||||
'cursor_created_at',
|
||||
'cursor_job_id',
|
||||
] as const)('rejects a cursor missing %s', (field) => {
|
||||
expect(ListJobsQuery.safeParse({...cursor, [field]: undefined})).toMatchObject({
|
||||
success: false,
|
||||
error: {issues: [{path: [field]}]},
|
||||
});
|
||||
});
|
||||
test.each(['cursor_bucket_day', 'cursor_created_at', 'cursor_job_id'] as const)(
|
||||
'rejects a cursor missing %s',
|
||||
(field) => {
|
||||
expect(ListJobsQuery.safeParse({...cursor, [field]: undefined})).toMatchObject({
|
||||
success: false,
|
||||
error: {issues: [{path: [field]}]},
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.each([
|
||||
{cursor_bucket_day: '2023-02-29'},
|
||||
|
||||
@@ -18,16 +18,12 @@ describe('MessageNonceRequest', () => {
|
||||
expect(MessageNonceRequest.parse(input)).toBe(expected);
|
||||
});
|
||||
|
||||
it.each([
|
||||
-1,
|
||||
0.5,
|
||||
Number.MAX_SAFE_INTEGER + 1,
|
||||
Number.POSITIVE_INFINITY,
|
||||
'',
|
||||
'a'.repeat(33),
|
||||
])('rejects invalid nonce %j', (input) => {
|
||||
expect(MessageNonceRequest.safeParse(input).success).toBe(false);
|
||||
});
|
||||
it.each([-1, 0.5, Number.MAX_SAFE_INTEGER + 1, Number.POSITIVE_INFINITY, '', 'a'.repeat(33)])(
|
||||
'rejects invalid nonce %j',
|
||||
(input) => {
|
||||
expect(MessageNonceRequest.safeParse(input).success).toBe(false);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('MessageRequestSchema', () => {
|
||||
|
||||
@@ -137,14 +137,12 @@ describe('application redirect policies', () => {
|
||||
])('accepts registered URI %s', (uri) => {
|
||||
expect(ApplicationCreateRequest.parse({name: 'Application', redirect_uris: [uri]}).redirect_uris).toEqual([uri]);
|
||||
});
|
||||
it.each([
|
||||
'http://example.com/callback',
|
||||
'https://',
|
||||
'/relative',
|
||||
'ftp://example.com/callback',
|
||||
])('rejects registered URI %s', (uri) => {
|
||||
expect(ApplicationCreateRequest.safeParse({name: 'Application', redirect_uris: [uri]}).success).toBe(false);
|
||||
});
|
||||
it.each(['http://example.com/callback', 'https://', '/relative', 'ftp://example.com/callback'])(
|
||||
'rejects registered URI %s',
|
||||
(uri) => {
|
||||
expect(ApplicationCreateRequest.safeParse({name: 'Application', redirect_uris: [uri]}).success).toBe(false);
|
||||
},
|
||||
);
|
||||
it('defaults missing create URIs but does not clear missing update URIs', () => {
|
||||
expect(ApplicationCreateRequest.parse({name: 'Application'})).toEqual({name: 'Application', redirect_uris: []});
|
||||
expect(ApplicationUpdateRequest.parse({})).toEqual({});
|
||||
|
||||
@@ -71,13 +71,12 @@ describe.each([
|
||||
{name: 'update body', schema: UpdateVoiceServerRequestBody, required: {}},
|
||||
{name: 'update service request', schema: UpdateVoiceServerRequest, required: {region_id: 'eu', server_id: 'primary'}},
|
||||
])('$name coordinates', ({schema, required}) => {
|
||||
it.each([
|
||||
{},
|
||||
{latitude: 0, longitude: 0},
|
||||
{latitude: null, longitude: null},
|
||||
])('accepts the paired state %j', (coordinates) => {
|
||||
expect(schema.parse({...required, ...coordinates})).toMatchObject(coordinates);
|
||||
});
|
||||
it.each([{}, {latitude: 0, longitude: 0}, {latitude: null, longitude: null}])(
|
||||
'accepts the paired state %j',
|
||||
(coordinates) => {
|
||||
expect(schema.parse({...required, ...coordinates})).toMatchObject(coordinates);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
{latitude: 0},
|
||||
@@ -163,15 +162,13 @@ describe.each([
|
||||
expect(schema.parse({})).toEqual(bulkDeleteDefaults);
|
||||
});
|
||||
|
||||
it.each([
|
||||
'include_dms',
|
||||
'include_dms_closed',
|
||||
'include_group_dms',
|
||||
'include_guilds',
|
||||
] as const)('accepts %s as the only selected context', (field) => {
|
||||
const selection = {...noSelectedContexts, [field]: true};
|
||||
expect(schema.parse(selection)).toEqual({...bulkDeleteDefaults, ...selection});
|
||||
});
|
||||
it.each(['include_dms', 'include_dms_closed', 'include_group_dms', 'include_guilds'] as const)(
|
||||
'accepts %s as the only selected context',
|
||||
(field) => {
|
||||
const selection = {...noSelectedContexts, [field]: true};
|
||||
expect(schema.parse(selection)).toEqual({...bulkDeleteDefaults, ...selection});
|
||||
},
|
||||
);
|
||||
|
||||
it('does not require selected contexts for inaccessible-only scope', () => {
|
||||
const selection = {...noSelectedContexts, scope: 'inaccessible_only'};
|
||||
|
||||
@@ -5,11 +5,12 @@ import {AuditLogActionTypeSchema} from '@fluxer/schema/src/primitives/AuditLogVa
|
||||
import {describe, expect, it} from 'vitest';
|
||||
|
||||
describe('AuditLogActionTypeSchema', () => {
|
||||
it.each(
|
||||
Object.values(AuditLogActionType).filter((value) => typeof value === 'number'),
|
||||
)('accepts registered action %i', (value) => {
|
||||
expect(AuditLogActionTypeSchema.parse(value)).toBe(value);
|
||||
});
|
||||
it.each(Object.values(AuditLogActionType).filter((value) => typeof value === 'number'))(
|
||||
'accepts registered action %i',
|
||||
(value) => {
|
||||
expect(AuditLogActionTypeSchema.parse(value)).toBe(value);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([0, 9, 999, -1, 1.5, '1', 'GUILD_UPDATE', null])('rejects unknown or nonnumeric action %j', (value) => {
|
||||
expect(AuditLogActionTypeSchema.safeParse(value).success).toBe(false);
|
||||
|
||||
@@ -53,21 +53,12 @@ describe('isValidBase64', () => {
|
||||
expect(isValidBase64(input)).toBe(true);
|
||||
});
|
||||
|
||||
it.each([
|
||||
'YQ',
|
||||
'YQ=',
|
||||
'YQ===',
|
||||
'====',
|
||||
'Y=Q=',
|
||||
'YR==',
|
||||
'YWJ=',
|
||||
'YWJ_',
|
||||
'YWJ-',
|
||||
'YW J',
|
||||
'éAAA',
|
||||
])('rejects malformed or noncanonical encoding %j', (input) => {
|
||||
expect(isValidBase64(input)).toBe(false);
|
||||
});
|
||||
it.each(['YQ', 'YQ=', 'YQ===', '====', 'Y=Q=', 'YR==', 'YWJ=', 'YWJ_', 'YWJ-', 'YW J', 'éAAA'])(
|
||||
'rejects malformed or noncanonical encoding %j',
|
||||
(input) => {
|
||||
expect(isValidBase64(input)).toBe(false);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([1, 2, 3, 255, 256])('accepts a byte round trip of length %i', (length) => {
|
||||
const bytes = Buffer.from(Array.from({length}, (_, index) => index % 256));
|
||||
@@ -137,13 +128,13 @@ describe('base64LengthForBytes', () => {
|
||||
expect(base64LengthForBytes(bytes) % 4).toBe(0);
|
||||
});
|
||||
|
||||
it.each([
|
||||
EMOJI_MAX_SIZE,
|
||||
EMOJI_MAX_SIZE + 1,
|
||||
])('accepts %i encoded bytes; decoded-byte limits remain authoritative', (bytes) => {
|
||||
const schema = createBase64StringType(1, base64LengthForBytes(EMOJI_MAX_SIZE));
|
||||
const encoded = Buffer.alloc(bytes, 1).toString('base64');
|
||||
expect(encoded.length).toBe(base64LengthForBytes(EMOJI_MAX_SIZE));
|
||||
expect(schema.parse(encoded)).toBe(encoded);
|
||||
});
|
||||
it.each([EMOJI_MAX_SIZE, EMOJI_MAX_SIZE + 1])(
|
||||
'accepts %i encoded bytes; decoded-byte limits remain authoritative',
|
||||
(bytes) => {
|
||||
const schema = createBase64StringType(1, base64LengthForBytes(EMOJI_MAX_SIZE));
|
||||
const encoded = Buffer.alloc(bytes, 1).toString('base64');
|
||||
expect(encoded.length).toBe(base64LengthForBytes(EMOJI_MAX_SIZE));
|
||||
expect(schema.parse(encoded)).toBe(encoded);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -50,10 +50,9 @@ it.each([1, 2])('rejects legacy NSFW level %i', (value) => {
|
||||
expect(NSFWLevelSchema.safeParse(value).success).toBe(false);
|
||||
});
|
||||
|
||||
it.each([
|
||||
MessageNotifications.NULL,
|
||||
MessageNotifications.NO_MESSAGES,
|
||||
MessageNotifications.INHERIT,
|
||||
])('rejects channel-only notification setting %i as a guild default', (value) => {
|
||||
expect(DefaultMessageNotificationsSchema.safeParse(value).success).toBe(false);
|
||||
});
|
||||
it.each([MessageNotifications.NULL, MessageNotifications.NO_MESSAGES, MessageNotifications.INHERIT])(
|
||||
'rejects channel-only notification setting %i as a guild default',
|
||||
(value) => {
|
||||
expect(DefaultMessageNotificationsSchema.safeParse(value).success).toBe(false);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -5,11 +5,12 @@ import {MessageReferenceTypeSchema, MessageTypeSchema} from '@fluxer/schema/src/
|
||||
import {describe, expect, it} from 'vitest';
|
||||
|
||||
describe('MessageTypeSchema', () => {
|
||||
it.each(
|
||||
Object.values(MessageTypes).filter((value) => value !== MessageTypes.CLIENT_SYSTEM),
|
||||
)('accepts wire message type %i', (value) => {
|
||||
expect(MessageTypeSchema.parse(value)).toBe(value);
|
||||
});
|
||||
it.each(Object.values(MessageTypes).filter((value) => value !== MessageTypes.CLIENT_SYSTEM))(
|
||||
'accepts wire message type %i',
|
||||
(value) => {
|
||||
expect(MessageTypeSchema.parse(value)).toBe(value);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([MessageTypes.CLIENT_SYSTEM, 8, -1, 0.5, '0', null])('rejects non-wire message type %j', (value) => {
|
||||
expect(MessageTypeSchema.safeParse(value).success).toBe(false);
|
||||
|
||||
@@ -40,24 +40,15 @@ describe('createQueryIntegerType', () => {
|
||||
expect(schema.parse(input)).toBe(expected);
|
||||
});
|
||||
|
||||
it.each([
|
||||
'3.14',
|
||||
'3.0',
|
||||
'42px',
|
||||
'1e2',
|
||||
'0x10',
|
||||
'',
|
||||
' ',
|
||||
'NaN',
|
||||
'Infinity',
|
||||
'-1',
|
||||
'2147483648',
|
||||
])('rejects %j without truncation or coercion', (input) => {
|
||||
expect(schema.safeParse(input)).toMatchObject({
|
||||
success: false,
|
||||
error: {issues: [{message: ValidationErrorCodes.VALUE_MUST_BE_INTEGER_IN_RANGE}]},
|
||||
});
|
||||
});
|
||||
it.each(['3.14', '3.0', '42px', '1e2', '0x10', '', ' ', 'NaN', 'Infinity', '-1', '2147483648'])(
|
||||
'rejects %j without truncation or coercion',
|
||||
(input) => {
|
||||
expect(schema.safeParse(input)).toMatchObject({
|
||||
success: false,
|
||||
error: {issues: [{message: ValidationErrorCodes.VALUE_MUST_BE_INTEGER_IN_RANGE}]},
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it.each(['-5', '5'])('accepts the configured range boundary %s', (input) => {
|
||||
expect(createQueryIntegerType({minValue: -5, maxValue: 5}).parse(input)).toBe(Number(input));
|
||||
|
||||
@@ -64,14 +64,12 @@ describe('Int64Type', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
Number.MAX_SAFE_INTEGER + 1,
|
||||
Number.NaN,
|
||||
Number.POSITIVE_INFINITY,
|
||||
1.5,
|
||||
])('rejects lossy or noninteger numeric input %j', (input) => {
|
||||
expect(Int64Type.safeParse(input).success).toBe(false);
|
||||
});
|
||||
it.each([Number.MAX_SAFE_INTEGER + 1, Number.NaN, Number.POSITIVE_INFINITY, 1.5])(
|
||||
'rejects lossy or noninteger numeric input %j',
|
||||
(input) => {
|
||||
expect(Int64Type.safeParse(input).success).toBe(false);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('Int64StringType', () => {
|
||||
@@ -92,14 +90,12 @@ describe('UnsignedInt64Type', () => {
|
||||
expect(UnsignedInt64Type.parse(input)).toBe(expected);
|
||||
});
|
||||
|
||||
it.each([
|
||||
'-1',
|
||||
'+1',
|
||||
'9223372036854775808',
|
||||
'18446744073709551615',
|
||||
])('rejects %s outside unsigned signed-64-bit storage', (input) => {
|
||||
expect(UnsignedInt64Type.safeParse(input).success).toBe(false);
|
||||
});
|
||||
it.each(['-1', '+1', '9223372036854775808', '18446744073709551615'])(
|
||||
'rejects %s outside unsigned signed-64-bit storage',
|
||||
(input) => {
|
||||
expect(UnsignedInt64Type.safeParse(input).success).toBe(false);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe('SnowflakeType', () => {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"extends": "../../tsconfigs/base.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"types": ["node"],
|
||||
"paths": {
|
||||
"@fluxer/*": ["./../../packages/*"]
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"typecheck": "tsgo --noEmit"
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluxer/constants": "workspace:*",
|
||||
@@ -21,7 +21,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"typescript": "catalog:ts7",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
"bench": "vitest bench --run",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"typecheck": "tsgo --noEmit"
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"typescript": "catalog:ts7",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import type {
|
||||
VoiceEngineV2ScreenOptions,
|
||||
VoiceEngineV2Stats,
|
||||
} from '@fluxer/voice_engine_v2/src/protocol/types';
|
||||
import {bench, describe} from 'vitest';
|
||||
import {test} from 'vitest';
|
||||
|
||||
interface VoiceEngineV2BenchFixture {
|
||||
events: Array<VoiceEngineV2Event>;
|
||||
@@ -100,28 +100,28 @@ const participantEvent: VoiceEngineV2Event = {
|
||||
const statsPayload: VoiceEngineV2Stats = Object.freeze({rttMs: 42, outbound: [], inbound: []});
|
||||
const statsEvent: VoiceEngineV2Event = {type: 'stats.collected', operationId: 9_999_999, stats: statsPayload};
|
||||
|
||||
describe('voice engine v2 reducer hot paths', () => {
|
||||
bench('inboundVideo.frameReceived', () => {
|
||||
test('voice engine v2 reducer hot paths', async ({bench}) => {
|
||||
await bench('inboundVideo.frameReceived', () => {
|
||||
transitionVoiceEngineV2(connectedSnapshot, frameEvent);
|
||||
});
|
||||
}).run();
|
||||
|
||||
bench('inboundVideo.frameStats', () => {
|
||||
await bench('inboundVideo.frameStats', () => {
|
||||
transitionVoiceEngineV2(connectedSnapshot, frameStatsEvent);
|
||||
});
|
||||
}).run();
|
||||
|
||||
bench('microphone.publishRequested', () => {
|
||||
await bench('microphone.publishRequested', () => {
|
||||
transitionVoiceEngineV2(connectedSnapshot, microphoneEvent);
|
||||
});
|
||||
}).run();
|
||||
|
||||
bench('screen.publishRequested', () => {
|
||||
await bench('screen.publishRequested', () => {
|
||||
transitionVoiceEngineV2(connectedSnapshot, screenEvent);
|
||||
});
|
||||
}).run();
|
||||
|
||||
bench('room.participantJoined', () => {
|
||||
await bench('room.participantJoined', () => {
|
||||
transitionVoiceEngineV2(connectedSnapshot, participantEvent);
|
||||
});
|
||||
}).run();
|
||||
|
||||
bench('stats.collected', () => {
|
||||
await bench('stats.collected', () => {
|
||||
transitionVoiceEngineV2(connectedSnapshot, statsEvent);
|
||||
});
|
||||
}).run();
|
||||
});
|
||||
|
||||
@@ -98,87 +98,88 @@ interface VoiceTrackClassificationFixture {
|
||||
}
|
||||
|
||||
describe('voice engine v2 policies', () => {
|
||||
it.each(
|
||||
microphoneFailureFixtures as Array<MicrophoneFailureFixture>,
|
||||
)('replays microphone failure action fixture: $name', ({result, requestedEnabled, context, expected}) => {
|
||||
expect(getVoiceEngineV2MicrophoneOperationFailureAction(result, requestedEnabled, context)).toBe(expected);
|
||||
});
|
||||
it.each(microphoneFailureFixtures as Array<MicrophoneFailureFixture>)(
|
||||
'replays microphone failure action fixture: $name',
|
||||
({result, requestedEnabled, context, expected}) => {
|
||||
expect(getVoiceEngineV2MicrophoneOperationFailureAction(result, requestedEnabled, context)).toBe(expected);
|
||||
},
|
||||
);
|
||||
|
||||
it.each(
|
||||
hardwareEncoderCapabilityFixtures as Array<HardwareEncoderCapabilityFixture>,
|
||||
)('replays hardware encoder capability fixture: $name', ({
|
||||
input,
|
||||
codec,
|
||||
expectedCapabilities,
|
||||
expectedNativeNvenc,
|
||||
}) => {
|
||||
const capabilities = normalizeVoiceEngineV2HardwareEncoderCapabilities(input);
|
||||
expect(capabilities).toMatchObject(expectedCapabilities);
|
||||
expect(hasVoiceEngineV2NativeNvencEncoder(capabilities, codec)).toBe(expectedNativeNvenc);
|
||||
});
|
||||
it.each(hardwareEncoderCapabilityFixtures as Array<HardwareEncoderCapabilityFixture>)(
|
||||
'replays hardware encoder capability fixture: $name',
|
||||
({input, codec, expectedCapabilities, expectedNativeNvenc}) => {
|
||||
const capabilities = normalizeVoiceEngineV2HardwareEncoderCapabilities(input);
|
||||
expect(capabilities).toMatchObject(expectedCapabilities);
|
||||
expect(hasVoiceEngineV2NativeNvencEncoder(capabilities, codec)).toBe(expectedNativeNvenc);
|
||||
},
|
||||
);
|
||||
|
||||
it.each(
|
||||
screenShareEncodingPlanFixtures as Array<ScreenShareEncodingPlanFixture>,
|
||||
)('replays screen-share encoding plan fixture: $name', (fixture) => {
|
||||
const plan = planVoiceEngineV2ScreenEncodingChange(fixture.input);
|
||||
expect(plan.action).toBe(fixture.expectedAction);
|
||||
expect(plan.reason).toBe(fixture.expectedReason);
|
||||
if (fixture.expectedCodec !== undefined) {
|
||||
expect(plan.desired?.codec).toBe(fixture.expectedCodec);
|
||||
}
|
||||
if (fixture.expectedHardwareEncoding !== undefined) {
|
||||
expect(plan.desired?.hardwareEncoding).toBe(fixture.expectedHardwareEncoding);
|
||||
}
|
||||
if (fixture.expectedZeroCopyRequired !== undefined) {
|
||||
expect(plan.desired?.zeroCopyRequired).toBe(fixture.expectedZeroCopyRequired);
|
||||
}
|
||||
if (fixture.expectedErrorCode !== undefined) {
|
||||
expect(plan.error?.code).toBe(fixture.expectedErrorCode);
|
||||
}
|
||||
});
|
||||
it.each(screenShareEncodingPlanFixtures as Array<ScreenShareEncodingPlanFixture>)(
|
||||
'replays screen-share encoding plan fixture: $name',
|
||||
(fixture) => {
|
||||
const plan = planVoiceEngineV2ScreenEncodingChange(fixture.input);
|
||||
expect(plan.action).toBe(fixture.expectedAction);
|
||||
expect(plan.reason).toBe(fixture.expectedReason);
|
||||
if (fixture.expectedCodec !== undefined) {
|
||||
expect(plan.desired?.codec).toBe(fixture.expectedCodec);
|
||||
}
|
||||
if (fixture.expectedHardwareEncoding !== undefined) {
|
||||
expect(plan.desired?.hardwareEncoding).toBe(fixture.expectedHardwareEncoding);
|
||||
}
|
||||
if (fixture.expectedZeroCopyRequired !== undefined) {
|
||||
expect(plan.desired?.zeroCopyRequired).toBe(fixture.expectedZeroCopyRequired);
|
||||
}
|
||||
if (fixture.expectedErrorCode !== undefined) {
|
||||
expect(plan.error?.code).toBe(fixture.expectedErrorCode);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it.each(
|
||||
cameraShareEncodingPlanFixtures as Array<CameraShareEncodingPlanFixture>,
|
||||
)('replays camera-share encoding plan fixture: $name', (fixture) => {
|
||||
const plan = planVoiceEngineV2CameraEncodingChange(fixture.input);
|
||||
expect(plan.action).toBe(fixture.expectedAction);
|
||||
expect(plan.reason).toBe(fixture.expectedReason);
|
||||
if (fixture.expectedCodec !== undefined) {
|
||||
expect(plan.desired?.codec).toBe(fixture.expectedCodec);
|
||||
}
|
||||
if (fixture.expectedMirror !== undefined) {
|
||||
expect(plan.desired?.mirror).toBe(fixture.expectedMirror);
|
||||
}
|
||||
if (fixture.expectedBackgroundMode !== undefined) {
|
||||
expect(plan.desired?.backgroundMode).toBe(fixture.expectedBackgroundMode);
|
||||
}
|
||||
if (fixture.expectedWidth !== undefined) {
|
||||
expect(plan.desired?.width).toBe(fixture.expectedWidth);
|
||||
}
|
||||
if (fixture.expectedFrameRate !== undefined) {
|
||||
expect(plan.desired?.frameRate).toBe(fixture.expectedFrameRate);
|
||||
}
|
||||
if (fixture.expectedErrorCode !== undefined) {
|
||||
expect(plan.error?.code).toBe(fixture.expectedErrorCode);
|
||||
}
|
||||
});
|
||||
it.each(cameraShareEncodingPlanFixtures as Array<CameraShareEncodingPlanFixture>)(
|
||||
'replays camera-share encoding plan fixture: $name',
|
||||
(fixture) => {
|
||||
const plan = planVoiceEngineV2CameraEncodingChange(fixture.input);
|
||||
expect(plan.action).toBe(fixture.expectedAction);
|
||||
expect(plan.reason).toBe(fixture.expectedReason);
|
||||
if (fixture.expectedCodec !== undefined) {
|
||||
expect(plan.desired?.codec).toBe(fixture.expectedCodec);
|
||||
}
|
||||
if (fixture.expectedMirror !== undefined) {
|
||||
expect(plan.desired?.mirror).toBe(fixture.expectedMirror);
|
||||
}
|
||||
if (fixture.expectedBackgroundMode !== undefined) {
|
||||
expect(plan.desired?.backgroundMode).toBe(fixture.expectedBackgroundMode);
|
||||
}
|
||||
if (fixture.expectedWidth !== undefined) {
|
||||
expect(plan.desired?.width).toBe(fixture.expectedWidth);
|
||||
}
|
||||
if (fixture.expectedFrameRate !== undefined) {
|
||||
expect(plan.desired?.frameRate).toBe(fixture.expectedFrameRate);
|
||||
}
|
||||
if (fixture.expectedErrorCode !== undefined) {
|
||||
expect(plan.error?.code).toBe(fixture.expectedErrorCode);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it.each(
|
||||
voiceStatsCoercionFixtures as Array<VoiceStatsCoercionFixture>,
|
||||
)('replays voice stats coercion fixture: $name', ({input, expected}) => {
|
||||
expect(coerceVoiceEngineV2Stats(input)).toMatchObject(expected);
|
||||
});
|
||||
it.each(voiceStatsCoercionFixtures as Array<VoiceStatsCoercionFixture>)(
|
||||
'replays voice stats coercion fixture: $name',
|
||||
({input, expected}) => {
|
||||
expect(coerceVoiceEngineV2Stats(input)).toMatchObject(expected);
|
||||
},
|
||||
);
|
||||
|
||||
it.each(voiceStatsSummaryFixtures as Array<VoiceStatsSummaryFixture>)('replays voice stats summary fixture: $name', ({
|
||||
input,
|
||||
expectedSummary,
|
||||
}) => {
|
||||
expect(summarizeVoiceEngineV2Stats(input)).toMatchObject(expectedSummary);
|
||||
});
|
||||
it.each(voiceStatsSummaryFixtures as Array<VoiceStatsSummaryFixture>)(
|
||||
'replays voice stats summary fixture: $name',
|
||||
({input, expectedSummary}) => {
|
||||
expect(summarizeVoiceEngineV2Stats(input)).toMatchObject(expectedSummary);
|
||||
},
|
||||
);
|
||||
|
||||
it.each(
|
||||
voiceTrackClassificationFixtures as Array<VoiceTrackClassificationFixture>,
|
||||
)('replays voice track classification fixture: $name', ({input, expected}) => {
|
||||
expect(classifyVoiceEngineV2TrackStats(input)).toEqual(expected);
|
||||
});
|
||||
it.each(voiceTrackClassificationFixtures as Array<VoiceTrackClassificationFixture>)(
|
||||
'replays voice track classification fixture: $name',
|
||||
({input, expected}) => {
|
||||
expect(classifyVoiceEngineV2TrackStats(input)).toEqual(expected);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -18,7 +18,7 @@ import type {
|
||||
} from '@fluxer/voice_engine_v2/src/protocol/types';
|
||||
import {createVoiceEngineV2MemoryEventLogSpillSink} from '@fluxer/voice_engine_v2/src/runtime/eventLogRing';
|
||||
import {VoiceEngineV2Runtime} from '@fluxer/voice_engine_v2/src/runtime/VoiceEngineV2Runtime';
|
||||
import {bench, describe} from 'vitest';
|
||||
import {test} from 'vitest';
|
||||
|
||||
interface VoiceEngineV2BenchFixture {
|
||||
events: Array<VoiceEngineV2Event>;
|
||||
@@ -108,24 +108,24 @@ const runtimeForScreen = buildRuntimeWithConnectedSession();
|
||||
const runtimeForParticipant = buildRuntimeWithConnectedSession();
|
||||
const runtimeForStats = buildRuntimeWithConnectedSession();
|
||||
|
||||
describe('voice engine v2 runtime dispatch round-trip', () => {
|
||||
bench('dispatch inboundVideo.frameReceived', () => {
|
||||
test('voice engine v2 runtime dispatch round-trip', async ({bench}) => {
|
||||
await bench('dispatch inboundVideo.frameReceived', () => {
|
||||
runtimeForFrames.dispatch(frameEvent);
|
||||
});
|
||||
}).run();
|
||||
|
||||
bench('dispatch microphone.publishRequested', () => {
|
||||
await bench('dispatch microphone.publishRequested', () => {
|
||||
runtimeForMicrophone.dispatch(microphoneEvent);
|
||||
});
|
||||
}).run();
|
||||
|
||||
bench('dispatch screen.publishRequested', () => {
|
||||
await bench('dispatch screen.publishRequested', () => {
|
||||
runtimeForScreen.dispatch(screenEvent);
|
||||
});
|
||||
}).run();
|
||||
|
||||
bench('dispatch room.participantJoined', () => {
|
||||
await bench('dispatch room.participantJoined', () => {
|
||||
runtimeForParticipant.dispatch(participantEvent);
|
||||
});
|
||||
}).run();
|
||||
|
||||
bench('dispatch stats.collected', () => {
|
||||
await bench('dispatch stats.collected', () => {
|
||||
runtimeForStats.dispatch(statsEvent);
|
||||
});
|
||||
}).run();
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ import type {
|
||||
VoiceEngineV2Track,
|
||||
VoiceEngineV2TrackSource,
|
||||
} from '@fluxer/voice_engine_v2/src/protocol/types';
|
||||
import {bench, describe} from 'vitest';
|
||||
import {test} from 'vitest';
|
||||
|
||||
const PARTICIPANT_COUNT = 8;
|
||||
const TRACKS_PER_PARTICIPANT = 4;
|
||||
@@ -56,16 +56,16 @@ function buildRealisticSnapshot(): VoiceEngineV2Snapshot {
|
||||
const realisticSnapshot = buildRealisticSnapshot();
|
||||
const serializedSnapshot = JSON.stringify(realisticSnapshot);
|
||||
|
||||
describe('voice engine v2 snapshot serialise/deserialise baseline', () => {
|
||||
bench('JSON.stringify snapshot (8 participants × 4 tracks)', () => {
|
||||
test('voice engine v2 snapshot serialise/deserialise baseline', async ({bench}) => {
|
||||
await bench('JSON.stringify snapshot (8 participants × 4 tracks)', () => {
|
||||
JSON.stringify(realisticSnapshot);
|
||||
});
|
||||
}).run();
|
||||
|
||||
bench('JSON.parse snapshot (8 participants × 4 tracks)', () => {
|
||||
await bench('JSON.parse snapshot (8 participants × 4 tracks)', () => {
|
||||
JSON.parse(serializedSnapshot);
|
||||
});
|
||||
}).run();
|
||||
|
||||
bench('JSON.stringify + JSON.parse round-trip', () => {
|
||||
await bench('JSON.stringify + JSON.parse round-trip', () => {
|
||||
JSON.parse(JSON.stringify(realisticSnapshot));
|
||||
});
|
||||
}).run();
|
||||
});
|
||||
|
||||
@@ -12,7 +12,6 @@ export default defineConfig({
|
||||
benchmark: {
|
||||
include: ['**/*.bench.{ts,tsx}'],
|
||||
exclude: ['node_modules', 'dist'],
|
||||
reporters: ['default'],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user