Repository: aiscript-dev/aiscript
Pull request #881 (2024-12-18 04:19:51)

Obj:pickを追加
関数~~Obj:extractとObj:extract_with_default~~`Obj:pick`を追加します。

## doc
#### @Obj:pick&lt;T&gt;(_o_: obj&lt;T&gt;, _keys_: arr&lt;str&gt;): obj&lt;T&gt;
オブジェクト`o`のプロパティのうち、キー名が`keys`に含まれるもののみを抽出します。  
`keys`にあって`o`にないキーは`NULL`になります。

codecov-commenter: :warning: Please install the !['codecov app svg image'](https://github.com/codecov/engineering-team/assets/152432831/e90313f4-9d3a-4b63-8b54-cfe14e7ec20d) to ensure uploads and comments are reliably processed by Codecov.

## [Codecov](https://app.codecov.io/gh/aiscript-dev/aiscript/pull/881?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
All modified and coverable lines are covered by tests :white_check_mark:

:exclamation: Your organization needs to install the [Codecov GitHub app](https://github.com/apps/codecov/installations/select_target) to enable full functionality.

| [Files with missing lines](https://app.codecov.io/gh/aiscript-dev/aiscript/pull/881?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | Coverage Δ | |
|---|---|---|
| [src/interpreter/lib/std.ts](https://app.codecov.io/gh/aiscript-dev/aiscript/pull/881?src=pr&el=tree&filepath=src%2Finterpreter%2Flib%2Fstd.ts&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-c3JjL2ludGVycHJldGVyL2xpYi9zdGQudHM=) | `77.54% <100.00%> (-1.69%)` | :arrow_down: |

... and [29 files with indirect coverage changes](https://app.codecov.io/gh/aiscript-dev/aiscript/pull/881/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)

uzmoi: 言語のstdに入れるほどの汎用性を感じないというかユースケースがわからないのですが、どんな使い方を想定していますか？
デフォルトは`Obj:merge(defaults, o)`とかでも代用できそうですが
FineArchs: > 言語のstdに入れるほどの汎用性を感じないというかユースケースがわからないのですが、どんな使い方を想定していますか？ デフォルトは`Obj:merge(defaults, o)`とかでも代用できそうですが

余計なキーを削除できるという点から、主な想定用途はモジュール化におけるアクセス制限です。
uzmoi: モジュール化のために既にあるオブジェクトのキーを絞るシチュエーションがわからないです


Patch:
diff --git a/etc/aiscript.api.md b/etc/aiscript.api.md
index f7b63bf..ed176ac 100644
--- a/etc/aiscript.api.md
+++ b/etc/aiscript.api.md
@@ -190,7 +190,9 @@ declare namespace Ast {
         Prop,
         TypeSource,
         NamedTypeSource,
-        FnTypeSource
+        FnTypeSource,
+        UnionTypeSource,
+        TypeParam
     }
 }
 export { Ast }
@@ -320,6 +322,7 @@ const FN: (params: VUserFn["params"], statements: VUserFn["statements"], scope:
 // @public (undocumented)
 type Fn = NodeBase & {
     type: 'fn';
+    typeParams: TypeParam[];
     params: {
         dest: Expression;
         optional: boolean;
@@ -336,6 +339,7 @@ const FN_NATIVE: (fn: VNativeFn["native"]) => VNativeFn;
 // @public (undocumented)
 type FnTypeSource = NodeBase & {
     type: 'fnTypeSource';
+    typeParams: TypeParam[];
     params: TypeSource[];
     result: TypeSource;
 };
@@ -718,8 +722,19 @@ const TRUE: {
     value: boolean;
 };
 
+// @public
+type TypeParam = {
+    name: string;
+};
+
 // @public (undocumented)
-type TypeSource = NamedTypeSource | FnTypeSource;
+type TypeSource = NamedTypeSource | FnTypeSource | UnionTypeSource;
+
+// @public (undocumented)
+type UnionTypeSource = NodeBase & {
+    type: 'unionTypeSource';
+    inners: TypeSource[];
+};
 
 declare namespace utils {
     export {
diff --git a/package-lock.json b/package-lock.json
index 4ccc899..b3f0339 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,21 +14,21 @@
 				"uuid": "11.0.3"
 			},
 			"devDependencies": {
-				"@eslint/js": "9.15.0",
-				"@microsoft/api-extractor": "7.48.0",
+				"@eslint/js": "9.17.0",
+				"@microsoft/api-extractor": "7.48.1",
 				"@types/eslint__js": "8.42.3",
-				"@types/node": "22.10.1",
+				"@types/node": "22.10.2",
 				"@types/seedrandom": "3.0.8",
 				"@types/uuid": "10.0.0",
-				"@vitest/coverage-v8": "2.1.6",
-				"chalk": "5.3.0",
-				"eslint": "9.15.0",
+				"@vitest/coverage-v8": "2.1.8",
+				"chalk": "5.4.1",
+				"eslint": "9.17.0",
 				"eslint-plugin-import": "2.31.0",
 				"semver": "7.6.3",
 				"ts-node": "10.9.2",
 				"typescript": "5.7.2",
-				"typescript-eslint": "8.16.0",
-				"vitest": "2.1.6"
+				"typescript-eslint": "8.18.2",
+				"vitest": "2.1.8"
 			}
 		},
 		"node_modules/@ampproject/remapping": {
@@ -128,9 +128,9 @@
 			}
 		},
 		"node_modules/@esbuild/aix-ppc64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz",
-			"integrity": "sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+			"integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
 			"cpu": [
 				"ppc64"
 			],
@@ -140,13 +140,13 @@
 				"aix"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/android-arm": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.0.tgz",
-			"integrity": "sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+			"integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
 			"cpu": [
 				"arm"
 			],
@@ -156,13 +156,13 @@
 				"android"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/android-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz",
-			"integrity": "sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+			"integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
 			"cpu": [
 				"arm64"
 			],
@@ -172,13 +172,13 @@
 				"android"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/android-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.0.tgz",
-			"integrity": "sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+			"integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
 			"cpu": [
 				"x64"
 			],
@@ -188,13 +188,13 @@
 				"android"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/darwin-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz",
-			"integrity": "sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+			"integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
 			"cpu": [
 				"arm64"
 			],
@@ -204,13 +204,13 @@
 				"darwin"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/darwin-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz",
-			"integrity": "sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+			"integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
 			"cpu": [
 				"x64"
 			],
@@ -220,13 +220,13 @@
 				"darwin"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/freebsd-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz",
-			"integrity": "sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+			"integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
 			"cpu": [
 				"arm64"
 			],
@@ -236,13 +236,13 @@
 				"freebsd"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/freebsd-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz",
-			"integrity": "sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+			"integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
 			"cpu": [
 				"x64"
 			],
@@ -252,13 +252,13 @@
 				"freebsd"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/linux-arm": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz",
-			"integrity": "sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+			"integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
 			"cpu": [
 				"arm"
 			],
@@ -268,13 +268,13 @@
 				"linux"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/linux-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz",
-			"integrity": "sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+			"integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
 			"cpu": [
 				"arm64"
 			],
@@ -284,13 +284,13 @@
 				"linux"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/linux-ia32": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz",
-			"integrity": "sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+			"integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
 			"cpu": [
 				"ia32"
 			],
@@ -300,13 +300,13 @@
 				"linux"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/linux-loong64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz",
-			"integrity": "sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+			"integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
 			"cpu": [
 				"loong64"
 			],
@@ -316,13 +316,13 @@
 				"linux"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/linux-mips64el": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz",
-			"integrity": "sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+			"integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
 			"cpu": [
 				"mips64el"
 			],
@@ -332,13 +332,13 @@
 				"linux"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/linux-ppc64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz",
-			"integrity": "sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+			"integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
 			"cpu": [
 				"ppc64"
 			],
@@ -348,13 +348,13 @@
 				"linux"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/linux-riscv64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz",
-			"integrity": "sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+			"integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
 			"cpu": [
 				"riscv64"
 			],
@@ -364,13 +364,13 @@
 				"linux"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/linux-s390x": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz",
-			"integrity": "sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+			"integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
 			"cpu": [
 				"s390x"
 			],
@@ -380,13 +380,13 @@
 				"linux"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/linux-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz",
-			"integrity": "sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+			"integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
 			"cpu": [
 				"x64"
 			],
@@ -396,13 +396,13 @@
 				"linux"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/netbsd-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz",
-			"integrity": "sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+			"integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
 			"cpu": [
 				"x64"
 			],
@@ -412,29 +412,13 @@
 				"netbsd"
 			],
 			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/openbsd-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz",
-			"integrity": "sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==",
-			"cpu": [
-				"arm64"
-			],
-			"dev": true,
-			"optional": true,
-			"os": [
-				"openbsd"
-			],
-			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/openbsd-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz",
-			"integrity": "sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+			"integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
 			"cpu": [
 				"x64"
 			],
@@ -444,13 +428,13 @@
 				"openbsd"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/sunos-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz",
-			"integrity": "sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+			"integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
 			"cpu": [
 				"x64"
 			],
@@ -460,13 +444,13 @@
 				"sunos"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/win32-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz",
-			"integrity": "sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+			"integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
 			"cpu": [
 				"arm64"
 			],
@@ -476,13 +460,13 @@
 				"win32"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/win32-ia32": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz",
-			"integrity": "sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+			"integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
 			"cpu": [
 				"ia32"
 			],
@@ -492,13 +476,13 @@
 				"win32"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@esbuild/win32-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz",
-			"integrity": "sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+			"integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
 			"cpu": [
 				"x64"
 			],
@@ -508,7 +492,7 @@
 				"win32"
 			],
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			}
 		},
 		"node_modules/@eslint-community/eslint-utils": {
@@ -642,9 +626,9 @@
 			}
 		},
 		"node_modules/@eslint/js": {
-			"version": "9.15.0",
-			"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz",
-			"integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==",
+			"version": "9.17.0",
+			"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz",
+			"integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==",
 			"dev": true,
 			"engines": {
 				"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -815,18 +799,18 @@
 			}
 		},
 		"node_modules/@microsoft/api-extractor": {
-			"version": "7.48.0",
-			"resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.48.0.tgz",
-			"integrity": "sha512-FMFgPjoilMUWeZXqYRlJ3gCVRhB7WU/HN88n8OLqEsmsG4zBdX/KQdtJfhq95LQTQ++zfu0Em1LLb73NqRCLYQ==",
+			"version": "7.48.1",
+			"resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.48.1.tgz",
+			"integrity": "sha512-HN9Osa1WxqLM66RaqB5nPAadx+nTIQmY/XtkFdaJvusjG8Tus++QqZtD7KPZDSkhEMGHsYeSyeU8qUzCDUXPjg==",
 			"dev": true,
 			"dependencies": {
-				"@microsoft/api-extractor-model": "7.30.0",
+				"@microsoft/api-extractor-model": "7.30.1",
 				"@microsoft/tsdoc": "~0.15.1",
 				"@microsoft/tsdoc-config": "~0.17.1",
-				"@rushstack/node-core-library": "5.10.0",
+				"@rushstack/node-core-library": "5.10.1",
 				"@rushstack/rig-package": "0.5.3",
-				"@rushstack/terminal": "0.14.3",
-				"@rushstack/ts-command-line": "4.23.1",
+				"@rushstack/terminal": "0.14.4",
+				"@rushstack/ts-command-line": "4.23.2",
 				"lodash": "~4.17.15",
 				"minimatch": "~3.0.3",
 				"resolve": "~1.22.1",
@@ -839,14 +823,14 @@
 			}
 		},
 		"node_modules/@microsoft/api-extractor-model": {
-			"version": "7.30.0",
-			"resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.30.0.tgz",
-			"integrity": "sha512-26/LJZBrsWDKAkOWRiQbdVgcfd1F3nyJnAiJzsAgpouPk7LtOIj7PK9aJtBaw/pUXrkotEg27RrT+Jm/q0bbug==",
+			"version": "7.30.1",
+			"resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.30.1.tgz",
+			"integrity": "sha512-CTS2PlASJHxVY8hqHORVb1HdECWOEMcMnM6/kDkPr0RZapAFSIHhg9D4jxuE8g+OWYHtPc10LCpmde5pylTRlA==",
 			"dev": true,
 			"dependencies": {
 				"@microsoft/tsdoc": "~0.15.1",
 				"@microsoft/tsdoc-config": "~0.17.1",
-				"@rushstack/node-core-library": "5.10.0"
+				"@rushstack/node-core-library": "5.10.1"
 			}
 		},
 		"node_modules/@microsoft/api-extractor/node_modules/lru-cache": {
@@ -957,9 +941,9 @@
 			}
 		},
 		"node_modules/@rollup/rollup-android-arm-eabi": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz",
-			"integrity": "sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.29.1.tgz",
+			"integrity": "sha512-ssKhA8RNltTZLpG6/QNkCSge+7mBQGUqJRisZ2MDQcEGaK93QESEgWK2iOpIDZ7k9zPVkG5AS3ksvD5ZWxmItw==",
 			"cpu": [
 				"arm"
 			],
@@ -970,9 +954,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-android-arm64": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz",
-			"integrity": "sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.29.1.tgz",
+			"integrity": "sha512-CaRfrV0cd+NIIcVVN/jx+hVLN+VRqnuzLRmfmlzpOzB87ajixsN/+9L5xNmkaUUvEbI5BmIKS+XTwXsHEb65Ew==",
 			"cpu": [
 				"arm64"
 			],
@@ -983,9 +967,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-darwin-arm64": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz",
-			"integrity": "sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.29.1.tgz",
+			"integrity": "sha512-2ORr7T31Y0Mnk6qNuwtyNmy14MunTAMx06VAPI6/Ju52W10zk1i7i5U3vlDRWjhOI5quBcrvhkCHyF76bI7kEw==",
 			"cpu": [
 				"arm64"
 			],
@@ -996,9 +980,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-darwin-x64": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz",
-			"integrity": "sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.29.1.tgz",
+			"integrity": "sha512-j/Ej1oanzPjmN0tirRd5K2/nncAhS9W6ICzgxV+9Y5ZsP0hiGhHJXZ2JQ53iSSjj8m6cRY6oB1GMzNn2EUt6Ng==",
 			"cpu": [
 				"x64"
 			],
@@ -1009,9 +993,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-freebsd-arm64": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz",
-			"integrity": "sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.29.1.tgz",
+			"integrity": "sha512-91C//G6Dm/cv724tpt7nTyP+JdN12iqeXGFM1SqnljCmi5yTXriH7B1r8AD9dAZByHpKAumqP1Qy2vVNIdLZqw==",
 			"cpu": [
 				"arm64"
 			],
@@ -1022,9 +1006,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-freebsd-x64": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz",
-			"integrity": "sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.29.1.tgz",
+			"integrity": "sha512-hEioiEQ9Dec2nIRoeHUP6hr1PSkXzQaCUyqBDQ9I9ik4gCXQZjJMIVzoNLBRGet+hIUb3CISMh9KXuCcWVW/8w==",
 			"cpu": [
 				"x64"
 			],
@@ -1035,9 +1019,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz",
-			"integrity": "sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.29.1.tgz",
+			"integrity": "sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A==",
 			"cpu": [
 				"arm"
 			],
@@ -1048,9 +1032,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-linux-arm-musleabihf": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz",
-			"integrity": "sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.29.1.tgz",
+			"integrity": "sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ==",
 			"cpu": [
 				"arm"
 			],
@@ -1061,9 +1045,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-linux-arm64-gnu": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz",
-			"integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.29.1.tgz",
+			"integrity": "sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA==",
 			"cpu": [
 				"arm64"
 			],
@@ -1074,9 +1058,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-linux-arm64-musl": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz",
-			"integrity": "sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.29.1.tgz",
+			"integrity": "sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA==",
 			"cpu": [
 				"arm64"
 			],
@@ -1086,10 +1070,23 @@
 				"linux"
 			]
 		},
+		"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.29.1.tgz",
+			"integrity": "sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw==",
+			"cpu": [
+				"loong64"
+			],
+			"dev": true,
+			"optional": true,
+			"os": [
+				"linux"
+			]
+		},
 		"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz",
-			"integrity": "sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.29.1.tgz",
+			"integrity": "sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w==",
 			"cpu": [
 				"ppc64"
 			],
@@ -1100,9 +1097,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-linux-riscv64-gnu": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz",
-			"integrity": "sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.29.1.tgz",
+			"integrity": "sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ==",
 			"cpu": [
 				"riscv64"
 			],
@@ -1113,9 +1110,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-linux-s390x-gnu": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz",
-			"integrity": "sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.29.1.tgz",
+			"integrity": "sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g==",
 			"cpu": [
 				"s390x"
 			],
@@ -1126,9 +1123,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-linux-x64-gnu": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz",
-			"integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.29.1.tgz",
+			"integrity": "sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ==",
 			"cpu": [
 				"x64"
 			],
@@ -1139,9 +1136,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-linux-x64-musl": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz",
-			"integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.29.1.tgz",
+			"integrity": "sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA==",
 			"cpu": [
 				"x64"
 			],
@@ -1152,9 +1149,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-win32-arm64-msvc": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz",
-			"integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.29.1.tgz",
+			"integrity": "sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig==",
 			"cpu": [
 				"arm64"
 			],
@@ -1165,9 +1162,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-win32-ia32-msvc": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz",
-			"integrity": "sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.29.1.tgz",
+			"integrity": "sha512-rYRe5S0FcjlOBZQHgbTKNrqxCBUmgDJem/VQTCcTnA2KCabYSWQDrytOzX7avb79cAAweNmMUb/Zw18RNd4mng==",
 			"cpu": [
 				"ia32"
 			],
@@ -1178,9 +1175,9 @@
 			]
 		},
 		"node_modules/@rollup/rollup-win32-x64-msvc": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz",
-			"integrity": "sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.29.1.tgz",
+			"integrity": "sha512-+10CMg9vt1MoHj6x1pxyjPSMjHTIlqs8/tBztXvPAx24SKs9jwVnKqHJumlH/IzhaPUaj3T6T6wfZr8okdXaIg==",
 			"cpu": [
 				"x64"
 			],
@@ -1198,9 +1195,9 @@
 			"license": "MIT"
 		},
 		"node_modules/@rushstack/node-core-library": {
-			"version": "5.10.0",
-			"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.10.0.tgz",
-			"integrity": "sha512-2pPLCuS/3x7DCd7liZkqOewGM0OzLyCacdvOe8j6Yrx9LkETGnxul1t7603bIaB8nUAooORcct9fFDOQMbWAgw==",
+			"version": "5.10.1",
+			"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.10.1.tgz",
+			"integrity": "sha512-BSb/KcyBHmUQwINrgtzo6jiH0HlGFmrUy33vO6unmceuVKTEyL2q+P0fQq2oB5hvXVWOEUhxB2QvlkZluvUEmg==",
 			"dev": true,
 			"dependencies": {
 				"ajv": "~8.13.0",
@@ -1276,12 +1273,12 @@
 			}
 		},
 		"node_modules/@rushstack/terminal": {
-			"version": "0.14.3",
-			"resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.14.3.tgz",
-			"integrity": "sha512-csXbZsAdab/v8DbU1sz7WC2aNaKArcdS/FPmXMOXEj/JBBZMvDK0+1b4Qao0kkG0ciB1Qe86/Mb68GjH6/TnMw==",
+			"version": "0.14.4",
+			"resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.14.4.tgz",
+			"integrity": "sha512-NxACqERW0PHq8Rpq1V6v5iTHEwkRGxenjEW+VWqRYQ8T9puUzgmGHmEZUaUEDHAe9Qyvp0/Ew04sAiQw9XjhJg==",
 			"dev": true,
 			"dependencies": {
-				"@rushstack/node-core-library": "5.10.0",
+				"@rushstack/node-core-library": "5.10.1",
 				"supports-color": "~8.1.1"
 			},
 			"peerDependencies": {
@@ -1294,12 +1291,12 @@
 			}
 		},
 		"node_modules/@rushstack/ts-command-line": {
-			"version": "4.23.1",
-			"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.23.1.tgz",
-			"integrity": "sha512-40jTmYoiu/xlIpkkRsVfENtBq4CW3R4azbL0Vmda+fMwHWqss6wwf/Cy/UJmMqIzpfYc2OTnjYP1ZLD3CmyeCA==",
+			"version": "4.23.2",
+			"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.23.2.tgz",
+			"integrity": "sha512-JJ7XZX5K3ThBBva38aomgsPv1L7FV6XmSOcR6HtM7HDFZJkepqT65imw26h9ggGqMjsY0R9jcl30tzKcVj9aOQ==",
 			"dev": true,
 			"dependencies": {
-				"@rushstack/terminal": "0.14.3",
+				"@rushstack/terminal": "0.14.4",
 				"@types/argparse": "1.0.38",
 				"argparse": "~1.0.9",
 				"string-argv": "~0.3.1"
@@ -1382,9 +1379,9 @@
 			"license": "MIT"
 		},
 		"node_modules/@types/node": {
-			"version": "22.10.1",
-			"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz",
-			"integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==",
+			"version": "22.10.2",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz",
+			"integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==",
 			"dev": true,
 			"dependencies": {
 				"undici-types": "~6.20.0"
@@ -1405,16 +1402,16 @@
 			"license": "MIT"
 		},
 		"node_modules/@typescript-eslint/eslint-plugin": {
-			"version": "8.16.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.16.0.tgz",
-			"integrity": "sha512-5YTHKV8MYlyMI6BaEG7crQ9BhSc8RxzshOReKwZwRWN0+XvvTOm+L/UYLCYxFpfwYuAAqhxiq4yae0CMFwbL7Q==",
+			"version": "8.18.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.2.tgz",
+			"integrity": "sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==",
 			"dev": true,
 			"dependencies": {
 				"@eslint-community/regexpp": "^4.10.0",
-				"@typescript-eslint/scope-manager": "8.16.0",
-				"@typescript-eslint/type-utils": "8.16.0",
-				"@typescript-eslint/utils": "8.16.0",
-				"@typescript-eslint/visitor-keys": "8.16.0",
+				"@typescript-eslint/scope-manager": "8.18.2",
+				"@typescript-eslint/type-utils": "8.18.2",
+				"@typescript-eslint/utils": "8.18.2",
+				"@typescript-eslint/visitor-keys": "8.18.2",
 				"graphemer": "^1.4.0",
 				"ignore": "^5.3.1",
 				"natural-compare": "^1.4.0",
@@ -1429,24 +1426,20 @@
 			},
 			"peerDependencies": {
 				"@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0",
-				"eslint": "^8.57.0 || ^9.0.0"
-			},
-			"peerDependenciesMeta": {
-				"typescript": {
-					"optional": true
-				}
+				"eslint": "^8.57.0 || ^9.0.0",
+				"typescript": ">=4.8.4 <5.8.0"
 			}
 		},
 		"node_modules/@typescript-eslint/parser": {
-			"version": "8.16.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.16.0.tgz",
-			"integrity": "sha512-D7DbgGFtsqIPIFMPJwCad9Gfi/hC0PWErRRHFnaCWoEDYi5tQUDiJCTmGUbBiLzjqAck4KcXt9Ayj0CNlIrF+w==",
+			"version": "8.18.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.2.tgz",
+			"integrity": "sha512-y7tcq4StgxQD4mDr9+Jb26dZ+HTZ/SkfqpXSiqeUXZHxOUyjWDKsmwKhJ0/tApR08DgOhrFAoAhyB80/p3ViuA==",
 			"dev": true,
 			"dependencies": {
-				"@typescript-eslint/scope-manager": "8.16.0",
-				"@typescript-eslint/types": "8.16.0",
-				"@typescript-eslint/typescript-estree": "8.16.0",
-				"@typescript-eslint/visitor-keys": "8.16.0",
+				"@typescript-eslint/scope-manager": "8.18.2",
+				"@typescript-eslint/types": "8.18.2",
+				"@typescript-eslint/typescript-estree": "8.18.2",
+				"@typescript-eslint/visitor-keys": "8.18.2",
 				"debug": "^4.3.4"
 			},
 			"engines": {
@@ -1457,22 +1450,18 @@
 				"url": "https://opencollective.com/typescript-eslint"
 			},
 			"peerDependencies": {
-				"eslint": "^8.57.0 || ^9.0.0"
-			},
-			"peerDependenciesMeta": {
-				"typescript": {
-					"optional": true
-				}
+				"eslint": "^8.57.0 || ^9.0.0",
+				"typescript": ">=4.8.4 <5.8.0"
 			}
 		},
 		"node_modules/@typescript-eslint/scope-manager": {
-			"version": "8.16.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.16.0.tgz",
-			"integrity": "sha512-mwsZWubQvBki2t5565uxF0EYvG+FwdFb8bMtDuGQLdCCnGPrDEDvm1gtfynuKlnpzeBRqdFCkMf9jg1fnAK8sg==",
+			"version": "8.18.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.2.tgz",
+			"integrity": "sha512-YJFSfbd0CJjy14r/EvWapYgV4R5CHzptssoag2M7y3Ra7XNta6GPAJPPP5KGB9j14viYXyrzRO5GkX7CRfo8/g==",
 			"dev": true,
 			"dependencies": {
-				"@typescript-eslint/types": "8.16.0",
-				"@typescript-eslint/visitor-keys": "8.16.0"
+				"@typescript-eslint/types": "8.18.2",
+				"@typescript-eslint/visitor-keys": "8.18.2"
 			},
 			"engines": {
 				"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1483,13 +1472,13 @@
 			}
 		},
 		"node_modules/@typescript-eslint/type-utils": {
-			"version": "8.16.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.16.0.tgz",
-			"integrity": "sha512-IqZHGG+g1XCWX9NyqnI/0CX5LL8/18awQqmkZSl2ynn8F76j579dByc0jhfVSnSnhf7zv76mKBQv9HQFKvDCgg==",
+			"version": "8.18.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.2.tgz",
+			"integrity": "sha512-AB/Wr1Lz31bzHfGm/jgbFR0VB0SML/hd2P1yxzKDM48YmP7vbyJNHRExUE/wZsQj2wUCvbWH8poNHFuxLqCTnA==",
 			"dev": true,
 			"dependencies": {
-				"@typescript-eslint/typescript-estree": "8.16.0",
-				"@typescript-eslint/utils": "8.16.0",
+				"@typescript-eslint/typescript-estree": "8.18.2",
+				"@typescript-eslint/utils": "8.18.2",
 				"debug": "^4.3.4",
 				"ts-api-utils": "^1.3.0"
 			},
@@ -1501,18 +1490,14 @@
 				"url": "https://opencollective.com/typescript-eslint"
 			},
 			"peerDependencies": {
-				"eslint": "^8.57.0 || ^9.0.0"
-			},
-			"peerDependenciesMeta": {
-				"typescript": {
-					"optional": true
-				}
+				"eslint": "^8.57.0 || ^9.0.0",
+				"typescript": ">=4.8.4 <5.8.0"
 			}
 		},
 		"node_modules/@typescript-eslint/types": {
-			"version": "8.16.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.16.0.tgz",
-			"integrity": "sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ==",
+			"version": "8.18.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.2.tgz",
+			"integrity": "sha512-Z/zblEPp8cIvmEn6+tPDIHUbRu/0z5lqZ+NvolL5SvXWT5rQy7+Nch83M0++XzO0XrWRFWECgOAyE8bsJTl1GQ==",
 			"dev": true,
 			"engines": {
 				"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1523,13 +1508,13 @@
 			}
 		},
 		"node_modules/@typescript-eslint/typescript-estree": {
-			"version": "8.16.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.16.0.tgz",
-			"integrity": "sha512-E2+9IzzXMc1iaBy9zmo+UYvluE3TW7bCGWSF41hVWUE01o8nzr1rvOQYSxelxr6StUvRcTMe633eY8mXASMaNw==",
+			"version": "8.18.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.2.tgz",
+			"integrity": "sha512-WXAVt595HjpmlfH4crSdM/1bcsqh+1weFRWIa9XMTx/XHZ9TCKMcr725tLYqWOgzKdeDrqVHxFotrvWcEsk2Tg==",
 			"dev": true,
 			"dependencies": {
-				"@typescript-eslint/types": "8.16.0",
-				"@typescript-eslint/visitor-keys": "8.16.0",
+				"@typescript-eslint/types": "8.18.2",
+				"@typescript-eslint/visitor-keys": "8.18.2",
 				"debug": "^4.3.4",
 				"fast-glob": "^3.3.2",
 				"is-glob": "^4.0.3",
@@ -1544,10 +1529,8 @@
 				"type": "opencollective",
 				"url": "https://opencollective.com/typescript-eslint"
 			},
-			"peerDependenciesMeta": {
-				"typescript": {
-					"optional": true
-				}
+			"peerDependencies": {
+				"typescript": ">=4.8.4 <5.8.0"
 			}
 		},
 		"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
@@ -1575,15 +1558,15 @@
 			}
 		},
 		"node_modules/@typescript-eslint/utils": {
-			"version": "8.16.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.16.0.tgz",
-			"integrity": "sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA==",
+			"version": "8.18.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.2.tgz",
+			"integrity": "sha512-Cr4A0H7DtVIPkauj4sTSXVl+VBWewE9/o40KcF3TV9aqDEOWoXF3/+oRXNby3DYzZeCATvbdksYsGZzplwnK/Q==",
 			"dev": true,
 			"dependencies": {
 				"@eslint-community/eslint-utils": "^4.4.0",
-				"@typescript-eslint/scope-manager": "8.16.0",
-				"@typescript-eslint/types": "8.16.0",
-				"@typescript-eslint/typescript-estree": "8.16.0"
+				"@typescript-eslint/scope-manager": "8.18.2",
+				"@typescript-eslint/types": "8.18.2",
+				"@typescript-eslint/typescript-estree": "8.18.2"
 			},
 			"engines": {
 				"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1593,21 +1576,17 @@
 				"url": "https://opencollective.com/typescript-eslint"
 			},
 			"peerDependencies": {
-				"eslint": "^8.57.0 || ^9.0.0"
-			},
-			"peerDependenciesMeta": {
-				"typescript": {
-					"optional": true
-				}
+				"eslint": "^8.57.0 || ^9.0.0",
+				"typescript": ">=4.8.4 <5.8.0"
 			}
 		},
 		"node_modules/@typescript-eslint/visitor-keys": {
-			"version": "8.16.0",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.16.0.tgz",
-			"integrity": "sha512-pq19gbaMOmFE3CbL0ZB8J8BFCo2ckfHBfaIsaOZgBIF4EoISJIdLX5xRhd0FGB0LlHReNRuzoJoMGpTjq8F2CQ==",
+			"version": "8.18.2",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.2.tgz",
+			"integrity": "sha512-zORcwn4C3trOWiCqFQP1x6G3xTRyZ1LYydnj51cRnJ6hxBlr/cKPckk+PKPUw/fXmvfKTcw7bwY3w9izgx5jZw==",
 			"dev": true,
 			"dependencies": {
-				"@typescript-eslint/types": "8.16.0",
+				"@typescript-eslint/types": "8.18.2",
 				"eslint-visitor-keys": "^4.2.0"
 			},
 			"engines": {
@@ -1619,9 +1598,9 @@
 			}
 		},
 		"node_modules/@vitest/coverage-v8": {
-			"version": "2.1.6",
-			"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.6.tgz",
-			"integrity": "sha512-qItJVYDbG3MUFO68dOZUz+rWlqe9LMzotERXFXKg25s2A/kSVsyS9O0yNGrITfBd943GsnBeQZkBUu7Pc+zVeA==",
+			"version": "2.1.8",
+			"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.8.tgz",
+			"integrity": "sha512-2Y7BPlKH18mAZYAW1tYByudlCYrQyl5RGvnnDYJKW5tCiO5qg3KSAy3XAxcxKz900a0ZXxWtKrMuZLe3lKBpJw==",
 			"dev": true,
 			"dependencies": {
 				"@ampproject/remapping": "^2.3.0",
@@ -1641,8 +1620,8 @@
 				"url": "https://opencollective.com/vitest"
 			},
 			"peerDependencies": {
-				"@vitest/browser": "2.1.6",
-				"vitest": "2.1.6"
+				"@vitest/browser": "2.1.8",
+				"vitest": "2.1.8"
 			},
 			"peerDependenciesMeta": {
 				"@vitest/browser": {
@@ -1651,13 +1630,13 @@
 			}
 		},
 		"node_modules/@vitest/expect": {
-			"version": "2.1.6",
-			"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.6.tgz",
-			"integrity": "sha512-9M1UR9CAmrhJOMoSwVnPh2rELPKhYo0m/CSgqw9PyStpxtkwhmdM6XYlXGKeYyERY1N6EIuzkQ7e3Lm1WKCoUg==",
+			"version": "2.1.8",
+			"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.8.tgz",
+			"integrity": "sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==",
 			"dev": true,
 			"dependencies": {
-				"@vitest/spy": "2.1.6",
-				"@vitest/utils": "2.1.6",
+				"@vitest/spy": "2.1.8",
+				"@vitest/utils": "2.1.8",
 				"chai": "^5.1.2",
 				"tinyrainbow": "^1.2.0"
 			},
@@ -1666,12 +1645,12 @@
 			}
 		},
 		"node_modules/@vitest/mocker": {
-			"version": "2.1.6",
-			"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.6.tgz",
-			"integrity": "sha512-MHZp2Z+Q/A3am5oD4WSH04f9B0T7UvwEb+v5W0kCYMhtXGYbdyl2NUk1wdSMqGthmhpiThPDp/hEoVwu16+u1A==",
+			"version": "2.1.8",
+			"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.8.tgz",
+			"integrity": "sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==",
 			"dev": true,
 			"dependencies": {
-				"@vitest/spy": "2.1.6",
+				"@vitest/spy": "2.1.8",
 				"estree-walker": "^3.0.3",
 				"magic-string": "^0.30.12"
 			},
@@ -1680,7 +1659,7 @@
 			},
 			"peerDependencies": {
 				"msw": "^2.4.9",
-				"vite": "^5.0.0 || ^6.0.0"
+				"vite": "^5.0.0"
 			},
 			"peerDependenciesMeta": {
 				"msw": {
@@ -1692,9 +1671,9 @@
 			}
 		},
 		"node_modules/@vitest/pretty-format": {
-			"version": "2.1.6",
-			"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.6.tgz",
-			"integrity": "sha512-exZyLcEnHgDMKc54TtHca4McV4sKT+NKAe9ix/yhd/qkYb/TP8HTyXRFDijV19qKqTZM0hPL4753zU/U8L/gAA==",
+			"version": "2.1.8",
+			"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.8.tgz",
+			"integrity": "sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==",
 			"dev": true,
 			"dependencies": {
 				"tinyrainbow": "^1.2.0"
@@ -1704,12 +1683,12 @@
 			}
 		},
 		"node_modules/@vitest/runner": {
-			"version": "2.1.6",
-			"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.6.tgz",
-			"integrity": "sha512-SjkRGSFyrA82m5nz7To4CkRSEVWn/rwQISHoia/DB8c6IHIhaE/UNAo+7UfeaeJRE979XceGl00LNkIz09RFsA==",
+			"version": "2.1.8",
+			"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.8.tgz",
+			"integrity": "sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==",
 			"dev": true,
 			"dependencies": {
-				"@vitest/utils": "2.1.6",
+				"@vitest/utils": "2.1.8",
 				"pathe": "^1.1.2"
 			},
 			"funding": {
@@ -1717,12 +1696,12 @@
 			}
 		},
 		"node_modules/@vitest/snapshot": {
-			"version": "2.1.6",
-			"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.6.tgz",
-			"integrity": "sha512-5JTWHw8iS9l3v4/VSuthCndw1lN/hpPB+mlgn1BUhFbobeIUj1J1V/Bj2t2ovGEmkXLTckFjQddsxS5T6LuVWw==",
+			"version": "2.1.8",
+			"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.8.tgz",
+			"integrity": "sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==",
 			"dev": true,
 			"dependencies": {
-				"@vitest/pretty-format": "2.1.6",
+				"@vitest/pretty-format": "2.1.8",
 				"magic-string": "^0.30.12",
 				"pathe": "^1.1.2"
 			},
@@ -1731,9 +1710,9 @@
 			}
 		},
 		"node_modules/@vitest/spy": {
-			"version": "2.1.6",
-			"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.6.tgz",
-			"integrity": "sha512-oTFObV8bd4SDdRka5O+mSh5w9irgx5IetrD5i+OsUUsk/shsBoHifwCzy45SAORzAhtNiprUVaK3hSCCzZh1jQ==",
+			"version": "2.1.8",
+			"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.8.tgz",
+			"integrity": "sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==",
 			"dev": true,
 			"dependencies": {
 				"tinyspy": "^3.0.2"
@@ -1743,12 +1722,12 @@
 			}
 		},
 		"node_modules/@vitest/utils": {
-			"version": "2.1.6",
-			"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.6.tgz",
-			"integrity": "sha512-ixNkFy3k4vokOUTU2blIUvOgKq/N2PW8vKIjZZYsGJCMX69MRa9J2sKqX5hY/k5O5Gty3YJChepkqZ3KM9LyIQ==",
+			"version": "2.1.8",
+			"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.8.tgz",
+			"integrity": "sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==",
 			"dev": true,
 			"dependencies": {
-				"@vitest/pretty-format": "2.1.6",
+				"@vitest/pretty-format": "2.1.8",
 				"loupe": "^3.1.2",
 				"tinyrainbow": "^1.2.0"
 			},
@@ -2109,11 +2088,10 @@
 			}
 		},
 		"node_modules/chalk": {
-			"version": "5.3.0",
-			"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
-			"integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
+			"version": "5.4.1",
+			"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
+			"integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
 			"dev": true,
-			"license": "MIT",
 			"engines": {
 				"node": "^12.17.0 || ^14.13 || >=16.0.0"
 			},
@@ -2495,42 +2473,41 @@
 			}
 		},
 		"node_modules/esbuild": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz",
-			"integrity": "sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==",
+			"version": "0.21.5",
+			"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
+			"integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
 			"dev": true,
 			"hasInstallScript": true,
 			"bin": {
 				"esbuild": "bin/esbuild"
 			},
 			"engines": {
-				"node": ">=18"
+				"node": ">=12"
 			},
 			"optionalDependencies": {
-				"@esbuild/aix-ppc64": "0.24.0",
-				"@esbuild/android-arm": "0.24.0",
-				"@esbuild/android-arm64": "0.24.0",
-				"@esbuild/android-x64": "0.24.0",
-				"@esbuild/darwin-arm64": "0.24.0",
-				"@esbuild/darwin-x64": "0.24.0",
-				"@esbuild/freebsd-arm64": "0.24.0",
-				"@esbuild/freebsd-x64": "0.24.0",
-				"@esbuild/linux-arm": "0.24.0",
-				"@esbuild/linux-arm64": "0.24.0",
-				"@esbuild/linux-ia32": "0.24.0",
-				"@esbuild/linux-loong64": "0.24.0",
-				"@esbuild/linux-mips64el": "0.24.0",
-				"@esbuild/linux-ppc64": "0.24.0",
-				"@esbuild/linux-riscv64": "0.24.0",
-				"@esbuild/linux-s390x": "0.24.0",
-				"@esbuild/linux-x64": "0.24.0",
-				"@esbuild/netbsd-x64": "0.24.0",
-				"@esbuild/openbsd-arm64": "0.24.0",
-				"@esbuild/openbsd-x64": "0.24.0",
-				"@esbuild/sunos-x64": "0.24.0",
-				"@esbuild/win32-arm64": "0.24.0",
-				"@esbuild/win32-ia32": "0.24.0",
-				"@esbuild/win32-x64": "0.24.0"
+				"@esbuild/aix-ppc64": "0.21.5",
+				"@esbuild/android-arm": "0.21.5",
+				"@esbuild/android-arm64": "0.21.5",
+				"@esbuild/android-x64": "0.21.5",
+				"@esbuild/darwin-arm64": "0.21.5",
+				"@esbuild/darwin-x64": "0.21.5",
+				"@esbuild/freebsd-arm64": "0.21.5",
+				"@esbuild/freebsd-x64": "0.21.5",
+				"@esbuild/linux-arm": "0.21.5",
+				"@esbuild/linux-arm64": "0.21.5",
+				"@esbuild/linux-ia32": "0.21.5",
+				"@esbuild/linux-loong64": "0.21.5",
+				"@esbuild/linux-mips64el": "0.21.5",
+				"@esbuild/linux-ppc64": "0.21.5",
+				"@esbuild/linux-riscv64": "0.21.5",
+				"@esbuild/linux-s390x": "0.21.5",
+				"@esbuild/linux-x64": "0.21.5",
+				"@esbuild/netbsd-x64": "0.21.5",
+				"@esbuild/openbsd-x64": "0.21.5",
+				"@esbuild/sunos-x64": "0.21.5",
+				"@esbuild/win32-arm64": "0.21.5",
+				"@esbuild/win32-ia32": "0.21.5",
+				"@esbuild/win32-x64": "0.21.5"
 			}
 		},
 		"node_modules/escape-string-regexp": {
@@ -2547,9 +2524,9 @@
 			}
 		},
 		"node_modules/eslint": {
-			"version": "9.15.0",
-			"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz",
-			"integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==",
+			"version": "9.17.0",
+			"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz",
+			"integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==",
 			"dev": true,
 			"dependencies": {
 				"@eslint-community/eslint-utils": "^4.2.0",
@@ -2557,7 +2534,7 @@
 				"@eslint/config-array": "^0.19.0",
 				"@eslint/core": "^0.9.0",
 				"@eslint/eslintrc": "^3.2.0",
-				"@eslint/js": "9.15.0",
+				"@eslint/js": "9.17.0",
 				"@eslint/plugin-kit": "^0.2.3",
 				"@humanfs/node": "^0.16.6",
 				"@humanwhocodes/module-importer": "^1.0.1",
@@ -2566,7 +2543,7 @@
 				"@types/json-schema": "^7.0.15",
 				"ajv": "^6.12.4",
 				"chalk": "^4.0.0",
-				"cross-spawn": "^7.0.5",
+				"cross-spawn": "^7.0.6",
 				"debug": "^4.3.2",
 				"escape-string-regexp": "^4.0.0",
 				"eslint-scope": "^8.2.0",
@@ -2963,9 +2940,9 @@
 			"license": "MIT"
 		},
 		"node_modules/fastq": {
-			"version": "1.17.1",
-			"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
-			"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+			"version": "1.18.0",
+			"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz",
+			"integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==",
 			"dev": true,
 			"dependencies": {
 				"reusify": "^1.0.4"
@@ -4453,9 +4430,9 @@
 			}
 		},
 		"node_modules/rollup": {
-			"version": "4.27.4",
-			"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz",
-			"integrity": "sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==",
+			"version": "4.29.1",
+			"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.29.1.tgz",
+			"integrity": "sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw==",
 			"dev": true,
 			"dependencies": {
 				"@types/estree": "1.0.6"
@@ -4468,24 +4445,25 @@
 				"npm": ">=8.0.0"
 			},
 			"optionalDependencies": {
-				"@rollup/rollup-android-arm-eabi": "4.27.4",
-				"@rollup/rollup-android-arm64": "4.27.4",
-				"@rollup/rollup-darwin-arm64": "4.27.4",
-				"@rollup/rollup-darwin-x64": "4.27.4",
-				"@rollup/rollup-freebsd-arm64": "4.27.4",
-				"@rollup/rollup-freebsd-x64": "4.27.4",
-				"@rollup/rollup-linux-arm-gnueabihf": "4.27.4",
-				"@rollup/rollup-linux-arm-musleabihf": "4.27.4",
-				"@rollup/rollup-linux-arm64-gnu": "4.27.4",
-				"@rollup/rollup-linux-arm64-musl": "4.27.4",
-				"@rollup/rollup-linux-powerpc64le-gnu": "4.27.4",
-				"@rollup/rollup-linux-riscv64-gnu": "4.27.4",
-				"@rollup/rollup-linux-s390x-gnu": "4.27.4",
-				"@rollup/rollup-linux-x64-gnu": "4.27.4",
-				"@rollup/rollup-linux-x64-musl": "4.27.4",
-				"@rollup/rollup-win32-arm64-msvc": "4.27.4",
-				"@rollup/rollup-win32-ia32-msvc": "4.27.4",
-				"@rollup/rollup-win32-x64-msvc": "4.27.4",
+				"@rollup/rollup-android-arm-eabi": "4.29.1",
+				"@rollup/rollup-android-arm64": "4.29.1",
+				"@rollup/rollup-darwin-arm64": "4.29.1",
+				"@rollup/rollup-darwin-x64": "4.29.1",
+				"@rollup/rollup-freebsd-arm64": "4.29.1",
+				"@rollup/rollup-freebsd-x64": "4.29.1",
+				"@rollup/rollup-linux-arm-gnueabihf": "4.29.1",
+				"@rollup/rollup-linux-arm-musleabihf": "4.29.1",
+				"@rollup/rollup-linux-arm64-gnu": "4.29.1",
+				"@rollup/rollup-linux-arm64-musl": "4.29.1",
+				"@rollup/rollup-linux-loongarch64-gnu": "4.29.1",
+				"@rollup/rollup-linux-powerpc64le-gnu": "4.29.1",
+				"@rollup/rollup-linux-riscv64-gnu": "4.29.1",
+				"@rollup/rollup-linux-s390x-gnu": "4.29.1",
+				"@rollup/rollup-linux-x64-gnu": "4.29.1",
+				"@rollup/rollup-linux-x64-musl": "4.29.1",
+				"@rollup/rollup-win32-arm64-msvc": "4.29.1",
+				"@rollup/rollup-win32-ia32-msvc": "4.29.1",
+				"@rollup/rollup-win32-x64-msvc": "4.29.1",
 				"fsevents": "~2.3.2"
 			}
 		},
@@ -5034,9 +5012,9 @@
 			}
 		},
 		"node_modules/ts-api-utils": {
-			"version": "1.4.2",
-			"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.2.tgz",
-			"integrity": "sha512-ZF5gQIQa/UmzfvxbHZI3JXN0/Jt+vnAfAviNRAMc491laiK6YCLpCW9ft8oaCRFOTxCZtUTE6XB0ZQAe3olntw==",
+			"version": "1.4.3",
+			"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz",
+			"integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==",
 			"dev": true,
 			"engines": {
 				"node": ">=16"
@@ -5206,14 +5184,14 @@
 			}
 		},
 		"node_modules/typescript-eslint": {
-			"version": "8.16.0",
-			"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.16.0.tgz",
-			"integrity": "sha512-wDkVmlY6O2do4V+lZd0GtRfbtXbeD0q9WygwXXSJnC1xorE8eqyC2L1tJimqpSeFrOzRlYtWnUp/uzgHQOgfBQ==",
+			"version": "8.18.2",
+			"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.18.2.tgz",
+			"integrity": "sha512-KuXezG6jHkvC3MvizeXgupZzaG5wjhU3yE8E7e6viOvAvD9xAWYp8/vy0WULTGe9DYDWcQu7aW03YIV3mSitrQ==",
 			"dev": true,
 			"dependencies": {
-				"@typescript-eslint/eslint-plugin": "8.16.0",
-				"@typescript-eslint/parser": "8.16.0",
-				"@typescript-eslint/utils": "8.16.0"
+				"@typescript-eslint/eslint-plugin": "8.18.2",
+				"@typescript-eslint/parser": "8.18.2",
+				"@typescript-eslint/utils": "8.18.2"
 			},
 			"engines": {
 				"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -5223,12 +5201,8 @@
 				"url": "https://opencollective.com/typescript-eslint"
 			},
 			"peerDependencies": {
-				"eslint": "^8.57.0 || ^9.0.0"
-			},
-			"peerDependenciesMeta": {
-				"typescript": {
-					"optional": true
-				}
+				"eslint": "^8.57.0 || ^9.0.0",
+				"typescript": ">=4.8.4 <5.8.0"
 			}
 		},
 		"node_modules/unbox-primitive": {
@@ -5292,20 +5266,20 @@
 			"license": "MIT"
 		},
 		"node_modules/vite": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/vite/-/vite-6.0.1.tgz",
-			"integrity": "sha512-Ldn6gorLGr4mCdFnmeAOLweJxZ34HjKnDm4HGo6P66IEqTxQb36VEdFJQENKxWjupNfoIjvRUnswjn1hpYEpjQ==",
+			"version": "5.4.11",
+			"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
+			"integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==",
 			"dev": true,
 			"dependencies": {
-				"esbuild": "^0.24.0",
-				"postcss": "^8.4.49",
-				"rollup": "^4.23.0"
+				"esbuild": "^0.21.3",
+				"postcss": "^8.4.43",
+				"rollup": "^4.20.0"
 			},
 			"bin": {
 				"vite": "bin/vite.js"
 			},
 			"engines": {
-				"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+				"node": "^18.0.0 || >=20.0.0"
 			},
 			"funding": {
 				"url": "https://github.com/vitejs/vite?sponsor=1"
@@ -5314,25 +5288,19 @@
 				"fsevents": "~2.3.3"
 			},
 			"peerDependencies": {
-				"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
-				"jiti": ">=1.21.0",
+				"@types/node": "^18.0.0 || >=20.0.0",
 				"less": "*",
 				"lightningcss": "^1.21.0",
 				"sass": "*",
 				"sass-embedded": "*",
 				"stylus": "*",
 				"sugarss": "*",
-				"terser": "^5.16.0",
-				"tsx": "^4.8.1",
-				"yaml": "^2.4.2"
+				"terser": "^5.4.0"
 			},
 			"peerDependenciesMeta": {
 				"@types/node": {
 					"optional": true
 				},
-				"jiti": {
-					"optional": true
-				},
 				"less": {
 					"optional": true
 				},
@@ -5353,50 +5321,44 @@
 				},
 				"terser": {
 					"optional": true
-				},
-				"tsx": {
-					"optional": true
-				},
-				"yaml": {
-					"optional": true
 				}
 			}
 		},
 		"node_modules/vite-node": {
-			"version": "2.1.6",
-			"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.6.tgz",
-			"integrity": "sha512-DBfJY0n9JUwnyLxPSSUmEePT21j8JZp/sR9n+/gBwQU6DcQOioPdb8/pibWfXForbirSagZCilseYIwaL3f95A==",
+			"version": "2.1.8",
+			"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.8.tgz",
+			"integrity": "sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==",
 			"dev": true,
 			"dependencies": {
 				"cac": "^6.7.14",
 				"debug": "^4.3.7",
 				"es-module-lexer": "^1.5.4",
 				"pathe": "^1.1.2",
-				"vite": "^5.0.0 || ^6.0.0"
+				"vite": "^5.0.0"
 			},
 			"bin": {
 				"vite-node": "vite-node.mjs"
 			},
 			"engines": {
-				"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+				"node": "^18.0.0 || >=20.0.0"
 			},
 			"funding": {
 				"url": "https://opencollective.com/vitest"
 			}
 		},
 		"node_modules/vitest": {
-			"version": "2.1.6",
-			"resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.6.tgz",
-			"integrity": "sha512-isUCkvPL30J4c5O5hgONeFRsDmlw6kzFEdLQHLezmDdKQHy8Ke/B/dgdTMEgU0vm+iZ0TjW8GuK83DiahBoKWQ==",
-			"dev": true,
-			"dependencies": {
-				"@vitest/expect": "2.1.6",
-				"@vitest/mocker": "2.1.6",
-				"@vitest/pretty-format": "^2.1.6",
-				"@vitest/runner": "2.1.6",
-				"@vitest/snapshot": "2.1.6",
-				"@vitest/spy": "2.1.6",
-				"@vitest/utils": "2.1.6",
+			"version": "2.1.8",
+			"resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.8.tgz",
+			"integrity": "sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==",
+			"dev": true,
+			"dependencies": {
+				"@vitest/expect": "2.1.8",
+				"@vitest/mocker": "2.1.8",
+				"@vitest/pretty-format": "^2.1.8",
+				"@vitest/runner": "2.1.8",
+				"@vitest/snapshot": "2.1.8",
+				"@vitest/spy": "2.1.8",
+				"@vitest/utils": "2.1.8",
 				"chai": "^5.1.2",
 				"debug": "^4.3.7",
 				"expect-type": "^1.1.0",
@@ -5407,24 +5369,24 @@
 				"tinyexec": "^0.3.1",
 				"tinypool": "^1.0.1",
 				"tinyrainbow": "^1.2.0",
-				"vite": "^5.0.0 || ^6.0.0",
-				"vite-node": "2.1.6",
+				"vite": "^5.0.0",
+				"vite-node": "2.1.8",
 				"why-is-node-running": "^2.3.0"
 			},
 			"bin": {
 				"vitest": "vitest.mjs"
 			},
 			"engines": {
-				"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+				"node": "^18.0.0 || >=20.0.0"
 			},
 			"funding": {
 				"url": "https://opencollective.com/vitest"
 			},
 			"peerDependencies": {
 				"@edge-runtime/vm": "*",
-				"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
-				"@vitest/browser": "2.1.6",
-				"@vitest/ui": "2.1.6",
+				"@types/node": "^18.0.0 || >=20.0.0",
+				"@vitest/browser": "2.1.8",
+				"@vitest/ui": "2.1.8",
 				"happy-dom": "*",
 				"jsdom": "*"
 			},
diff --git a/package.json b/package.json
index a1b241d..31c7c3f 100644
--- a/package.json
+++ b/package.json
@@ -33,21 +33,21 @@
 		"prepublishOnly": "node scripts/check-release.mjs"
 	},
 	"devDependencies": {
-		"@eslint/js": "9.15.0",
-		"@microsoft/api-extractor": "7.48.0",
+		"@eslint/js": "9.17.0",
+		"@microsoft/api-extractor": "7.48.1",
 		"@types/eslint__js": "8.42.3",
-		"@types/node": "22.10.1",
+		"@types/node": "22.10.2",
 		"@types/seedrandom": "3.0.8",
 		"@types/uuid": "10.0.0",
-		"@vitest/coverage-v8": "2.1.6",
-		"chalk": "5.3.0",
-		"eslint": "9.15.0",
+		"@vitest/coverage-v8": "2.1.8",
+		"chalk": "5.4.1",
+		"eslint": "9.17.0",
 		"eslint-plugin-import": "2.31.0",
 		"semver": "7.6.3",
 		"ts-node": "10.9.2",
 		"typescript": "5.7.2",
-		"typescript-eslint": "8.16.0",
-		"vitest": "2.1.6"
+		"typescript-eslint": "8.18.2",
+		"vitest": "2.1.8"
 	},
 	"dependencies": {
 		"seedrandom": "3.0.5",
diff --git a/playground/package-lock.json b/playground/package-lock.json
index 806ce54..0d7c797 100644
--- a/playground/package-lock.json
+++ b/playground/package-lock.json
@@ -26,24 +26,24 @@
       "dependencies": {
         "seedrandom": "3.0.5",
         "stringz": "2.1.0",
-        "uuid": "10.0.0"
+        "uuid": "11.0.3"
       },
       "devDependencies": {
-        "@eslint/js": "9.13.0",
-        "@microsoft/api-extractor": "7.47.11",
+        "@eslint/js": "9.15.0",
+        "@microsoft/api-extractor": "7.48.0",
         "@types/eslint__js": "8.42.3",
-        "@types/node": "22.7.9",
+        "@types/node": "22.10.1",
         "@types/seedrandom": "3.0.8",
         "@types/uuid": "10.0.0",
-        "@vitest/coverage-v8": "2.1.3",
+        "@vitest/coverage-v8": "2.1.6",
         "chalk": "5.3.0",
-        "eslint": "9.13.0",
+        "eslint": "9.15.0",
         "eslint-plugin-import": "2.31.0",
         "semver": "7.6.3",
         "ts-node": "10.9.2",
-        "typescript": "5.6.3",
-        "typescript-eslint": "8.11.0",
-        "vitest": "2.1.3"
+        "typescript": "5.7.2",
+        "typescript-eslint": "8.16.0",
+        "vitest": "2.1.6"
       }
     },
     "node_modules/@babel/helper-string-parser": {
@@ -847,9 +847,9 @@
       }
     },
     "node_modules/nanoid": {
-      "version": "3.3.7",
-      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
-      "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+      "version": "3.3.8",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
+      "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
       "funding": [
         {
           "type": "github",
diff --git a/src/interpreter/index.ts b/src/interpreter/index.ts
index 2d89264..acc12d2 100644
--- a/src/interpreter/index.ts
+++ b/src/interpreter/index.ts
@@ -833,6 +833,7 @@ export class Interpreter {
 
 			case 'namedTypeSource':
 			case 'fnTypeSource':
+			case 'unionTypeSource':
 			case 'attr': {
 				throw new Error('invalid node type');
 			}
diff --git a/src/interpreter/lib/std.ts b/src/interpreter/lib/std.ts
index 178bc7f..3436ac0 100644
--- a/src/interpreter/lib/std.ts
+++ b/src/interpreter/lib/std.ts
@@ -620,6 +620,17 @@ export const std: Record<string, Value> = {
 		assertObject(b);
 		return OBJ(new Map([...a.value, ...b.value]));
 	}),
+
+	'Obj:pick': FN_NATIVE(([obj, keys]) => {
+		assertObject(obj);
+		assertArray(keys);
+		return OBJ(new Map(
+			keys.value.map(key => {
+				assertString(key);
+				return [key.value, obj.value.get(key.value) ?? NULL];
+			})
+		));
+	}),
 	//#endregion
 	
 	//#region Error
diff --git a/src/node.ts b/src/node.ts
index 19e94e9..2c73d69 100644
--- a/src/node.ts
+++ b/src/node.ts
@@ -276,6 +276,7 @@ export type If = NodeBase & {
 
 export type Fn = NodeBase & {
 	type: 'fn'; // 関数
+	typeParams: TypeParam[]; // 型パラメータ
 	params: {
 		dest: Expression; // 引数名
 		optional: boolean;
@@ -365,7 +366,7 @@ export type Prop = NodeBase & {
 
 // Type source
 
-export type TypeSource = NamedTypeSource | FnTypeSource;
+export type TypeSource = NamedTypeSource | FnTypeSource | UnionTypeSource;
 
 export type NamedTypeSource = NodeBase & {
 	type: 'namedTypeSource'; // 名前付き型
@@ -375,6 +376,19 @@ export type NamedTypeSource = NodeBase & {
 
 export type FnTypeSource = NodeBase & {
 	type: 'fnTypeSource'; // 関数の型
+	typeParams: TypeParam[]; // 型パラメータ
 	params: TypeSource[]; // 引数の型
 	result: TypeSource; // 戻り値の型
 };
+
+export type UnionTypeSource = NodeBase & {
+	type: 'unionTypeSource'; // ユニオン型
+	inners: TypeSource[]; // 含まれる型
+};
+
+/**
+ * 型パラメータ
+ */
+export type TypeParam = {
+	name: string; // パラメータ名
+}
diff --git a/src/parser/plugins/validate-keyword.ts b/src/parser/plugins/validate-keyword.ts
index 024a1de..9ccfad7 100644
--- a/src/parser/plugins/validate-keyword.ts
+++ b/src/parser/plugins/validate-keyword.ts
@@ -79,6 +79,14 @@ function validateDest(node: Ast.Node): Ast.Node {
 	});
 }
 
+function validateTypeParams(node: Ast.Fn | Ast.FnTypeSource): void {
+	for (const typeParam of node.typeParams) {
+		if (reservedWord.includes(typeParam.name)) {
+			throwReservedWordError(typeParam.name, node.loc);
+		}
+	}
+}
+
 function validateNode(node: Ast.Node): Ast.Node {
 	switch (node.type) {
 		case 'def': {
@@ -111,6 +119,7 @@ function validateNode(node: Ast.Node): Ast.Node {
 			break;
 		}
 		case 'fn': {
+			validateTypeParams(node);
 			for (const param of node.params) {
 				validateDest(param.dest);
 			}
@@ -124,6 +133,16 @@ function validateNode(node: Ast.Node): Ast.Node {
 			}
 			break;
 		}
+		case 'namedTypeSource': {
+			if (reservedWord.includes(node.name)) {
+				throwReservedWordError(node.name, node.loc);
+			}
+			break;
+		}
+		case 'fnTypeSource': {
+			validateTypeParams(node);
+			break;
+		}
 	}
 
 	return node;
diff --git a/src/parser/plugins/validate-type.ts b/src/parser/plugins/validate-type.ts
index 6fc8660..1d04391 100644
--- a/src/parser/plugins/validate-type.ts
+++ b/src/parser/plugins/validate-type.ts
@@ -2,22 +2,43 @@ import { getTypeBySource } from '../../type.js';
 import { visitNode } from '../visit.js';
 import type * as Ast from '../../node.js';
 
-function validateNode(node: Ast.Node): Ast.Node {
+function collectTypeParams(node: Ast.Node, ancestors: Ast.Node[]): Ast.TypeParam[] {
+	const items = [];
+	if (node.type === 'fn') {
+		const typeParamNames = new Set<string>();
+		for (const typeParam of node.typeParams) {
+			if (typeParamNames.has(typeParam.name)) {
+				throw new Error(`type parameter name ${typeParam.name} is duplicate`);
+			}
+			typeParamNames.add(typeParam.name);
+		}
+		items.push(...node.typeParams);
+	}
+	for (let i = ancestors.length - 1; i >= 0; i--) {
+		const ancestor = ancestors[i]!;
+		if (ancestor.type === 'fn') {
+			items.push(...ancestor.typeParams);
+		}
+	}
+	return items;
+}
+
+function validateNode(node: Ast.Node, ancestors: Ast.Node[]): Ast.Node {
 	switch (node.type) {
 		case 'def': {
 			if (node.varType != null) {
-				getTypeBySource(node.varType);
+				getTypeBySource(node.varType, collectTypeParams(node, ancestors));
 			}
 			break;
 		}
 		case 'fn': {
 			for (const param of node.params) {
 				if (param.argType != null) {
-					getTypeBySource(param.argType);
+					getTypeBySource(param.argType, collectTypeParams(node, ancestors));
 				}
 			}
 			if (node.retType != null) {
-				getTypeBySource(node.retType);
+				getTypeBySource(node.retType, collectTypeParams(node, ancestors));
 			}
 			break;
 		}
diff --git a/src/parser/scanner.ts b/src/parser/scanner.ts
index 401f2bd..5cab470 100644
--- a/src/parser/scanner.ts
+++ b/src/parser/scanner.ts
@@ -304,7 +304,7 @@ export class Scanner implements ITokenStream {
 						this.stream.next();
 						return TOKEN(TokenKind.Or2, pos, { hasLeftSpacing });
 					} else {
-						throw new AiScriptSyntaxError('invalid character: "|"', pos);
+						return TOKEN(TokenKind.Or, pos, { hasLeftSpacing });
 					}
 				}
 				case '}': {
diff --git a/src/parser/syntaxes/common.ts b/src/parser/syntaxes/common.ts
index a921682..946c112 100644
--- a/src/parser/syntaxes/common.ts
+++ b/src/parser/syntaxes/common.ts
@@ -3,6 +3,7 @@ import { AiScriptSyntaxError, AiScriptUnexpectedEOFError } from '../../error.js'
 import { NODE } from '../utils.js';
 import { parseStatement } from './statements.js';
 import { parseExpr } from './expressions.js';
+import { parseType } from './types.js';
 
 import type { ITokenStream } from '../streams/token-stream.js';
 import type * as Ast from '../../node.js';
@@ -134,16 +135,6 @@ export function parseBlock(s: ITokenStream): (Ast.Statement | Ast.Expression)[]
 	return steps;
 }
 
-//#region Type
-
-export function parseType(s: ITokenStream): Ast.TypeSource {
-	if (s.is(TokenKind.At)) {
-		return parseFnType(s);
-	} else {
-		return parseNamedType(s);
-	}
-}
-
 /**
  * ```abnf
  * OptionalSeparator = [SEP]
@@ -167,79 +158,3 @@ export function parseOptionalSeparator(s: ITokenStream): boolean {
 		}
 	}
 }
-
-/**
- * ```abnf
- * FnType = "@" "(" ParamTypes ")" "=>" Type
- * ParamTypes = [Type *(SEP Type)]
- * ```
-*/
-function parseFnType(s: ITokenStream): Ast.TypeSource {
-	const startPos = s.getPos();
-
-	s.expect(TokenKind.At);
-	s.next();
-	s.expect(TokenKind.OpenParen);
-	s.next();
-
-	const params: Ast.TypeSource[] = [];
-	while (!s.is(TokenKind.CloseParen)) {
-		if (params.length > 0) {
-			switch (s.getTokenKind()) {
-				case TokenKind.Comma: {
-					s.next();
-					break;
-				}
-				case TokenKind.EOF: {
-					throw new AiScriptUnexpectedEOFError(s.getPos());
-				}
-				default: {
-					throw new AiScriptSyntaxError('separator expected', s.getPos());
-				}
-			}
-		}
-		const type = parseType(s);
-		params.push(type);
-	}
-
-	s.expect(TokenKind.CloseParen);
-	s.next();
-	s.expect(TokenKind.Arrow);
-	s.next();
-
-	const resultType = parseType(s);
-
-	return NODE('fnTypeSource', { params, result: resultType }, startPos, s.getPos());
-}
-
-/**
- * ```abnf
- * NamedType = IDENT ["<" Type ">"]
- * ```
-*/
-function parseNamedType(s: ITokenStream): Ast.TypeSource {
-	const startPos = s.getPos();
-
-	let name: string;
-	if (s.is(TokenKind.Identifier)) {
-		name = s.getTokenValue();
-		s.next();
-	} else {
-		s.expect(TokenKind.NullKeyword);
-		s.next();
-		name = "null";
-	}
-
-	// inner type
-	let inner: Ast.TypeSource | undefined;
-	if (s.is(TokenKind.Lt)) {
-		s.next();
-		inner = parseType(s);
-		s.expect(TokenKind.Gt);
-		s.next();
-	}
-
-	return NODE('namedTypeSource', { name, inner }, startPos, s.getPos());
-}
-
-//#endregion Type
diff --git a/src/parser/syntaxes/expressions.ts b/src/parser/syntaxes/expressions.ts
index 8ef6b35..5d6e264 100644
--- a/src/parser/syntaxes/expressions.ts
+++ b/src/parser/syntaxes/expressions.ts
@@ -2,8 +2,9 @@ import { AiScriptSyntaxError, AiScriptUnexpectedEOFError } from '../../error.js'
 import { NODE, unexpectedTokenError } from '../utils.js';
 import { TokenStream } from '../streams/token-stream.js';
 import { TokenKind } from '../token.js';
-import { parseBlock, parseOptionalSeparator, parseParams, parseType } from './common.js';
+import { parseBlock, parseOptionalSeparator, parseParams } from './common.js';
 import { parseBlockOrStatement } from './statements.js';
+import { parseType, parseTypeParams } from './types.js';
 
 import type * as Ast from '../../node.js';
 import type { ITokenStream } from '../streams/token-stream.js';
@@ -381,7 +382,7 @@ function parseIf(s: ITokenStream): Ast.If {
 
 /**
  * ```abnf
- * FnExpr = "@" Params [":" Type] Block
+ * FnExpr = "@" [TypeParams] Params [":" Type] Block
  * ```
 */
 function parseFnExpr(s: ITokenStream): Ast.Fn {
@@ -390,6 +391,13 @@ function parseFnExpr(s: ITokenStream): Ast.Fn {
 	s.expect(TokenKind.At);
 	s.next();
 
+	let typeParams: Ast.TypeParam[];
+	if (s.is(TokenKind.Lt)) {
+		typeParams = parseTypeParams(s);
+	} else {
+		typeParams = [];
+	}
+
 	const params = parseParams(s);
 
 	let type: Ast.TypeSource | undefined;
@@ -400,7 +408,7 @@ function parseFnExpr(s: ITokenStream): Ast.Fn {
 
 	const body = parseBlock(s);
 
-	return NODE('fn', { params: params, retType: type, children: body }, startPos, s.getPos());
+	return NODE('fn', { typeParams, params, retType: type, children: body }, startPos, s.getPos());
 }
 
 /**
diff --git a/src/parser/syntaxes/statements.ts b/src/parser/syntaxes/statements.ts
index 5097313..050c15d 100644
--- a/src/parser/syntaxes/statements.ts
+++ b/src/parser/syntaxes/statements.ts
@@ -1,8 +1,9 @@
 import { AiScriptSyntaxError } from '../../error.js';
 import { CALL_NODE, NODE, unexpectedTokenError } from '../utils.js';
 import { TokenKind } from '../token.js';
-import { parseBlock, parseDest, parseParams, parseType } from './common.js';
+import { parseBlock, parseDest, parseParams } from './common.js';
 import { parseExpr } from './expressions.js';
+import { parseType, parseTypeParams } from './types.js';
 
 import type * as Ast from '../../node.js';
 import type { ITokenStream } from '../streams/token-stream.js';
@@ -144,7 +145,7 @@ function parseVarDef(s: ITokenStream): Ast.Definition {
 
 /**
  * ```abnf
- * FnDef = "@" IDENT Params [":" Type] Block
+ * FnDef = "@" IDENT [TypeParams] Params [":" Type] Block
  * ```
 */
 function parseFnDef(s: ITokenStream): Ast.Definition {
@@ -159,6 +160,13 @@ function parseFnDef(s: ITokenStream): Ast.Definition {
 	s.next();
 	const dest = NODE('identifier', { name }, nameStartPos, s.getPos());
 
+	let typeParams: Ast.TypeParam[];
+	if (s.is(TokenKind.Lt)) {
+		typeParams = parseTypeParams(s);
+	} else {
+		typeParams = [];
+	}
+
 	const params = parseParams(s);
 
 	let type: Ast.TypeSource | undefined;
@@ -174,6 +182,7 @@ function parseFnDef(s: ITokenStream): Ast.Definition {
 	return NODE('def', {
 		dest,
 		expr: NODE('fn', {
+			typeParams,
 			params: params,
 			retType: type,
 			children: body,
diff --git a/src/parser/syntaxes/types.ts b/src/parser/syntaxes/types.ts
new file mode 100644
index 0000000..a29ced1
--- /dev/null
+++ b/src/parser/syntaxes/types.ts
@@ -0,0 +1,176 @@
+import { AiScriptSyntaxError, AiScriptUnexpectedEOFError } from '../../error.js';
+import { TokenKind } from '../token.js';
+import { NODE } from '../utils.js';
+import { parseOptionalSeparator } from './common.js';
+
+import type { Ast } from '../../index.js';
+import type { ITokenStream } from '../streams/token-stream.js';
+import type { TypeParam } from '../../node.js';
+
+/**
+ * ```abnf
+ * Type = FnType / NamedType
+ * ```
+*/
+export function parseType(s: ITokenStream): Ast.TypeSource {
+	return parseUnionType(s);
+}
+
+/**
+ * ```abnf
+ * TypeParams = "<" TypeParam *(SEP TypeParam) [SEP] ">"
+ * ```
+*/
+export function parseTypeParams(s: ITokenStream): TypeParam[] {
+	s.expect(TokenKind.Lt);
+	s.next();
+
+	if (s.is(TokenKind.NewLine)) {
+		s.next();
+	}
+
+	const items: TypeParam[] = [parseTypeParam(s)];
+
+	while (parseOptionalSeparator(s)) {
+		if (s.is(TokenKind.Gt)) {
+			break;
+		}
+		const item = parseTypeParam(s);
+		items.push(item);
+	}
+
+	s.expect(TokenKind.Gt);
+	s.next();
+
+	return items;
+}
+
+/**
+ * ```abnf
+ * TypeParam = IDENT
+ * ```
+*/
+function parseTypeParam(s: ITokenStream): TypeParam {
+	s.expect(TokenKind.Identifier);
+	const name = s.getTokenValue();
+	s.next();
+
+	return { name };
+}
+
+/**
+ * ```abnf
+ * UnionType = UnionTypeInner *("|" UnionTypeInner)
+ * ```
+*/
+function parseUnionType(s: ITokenStream): Ast.TypeSource {
+	const startPos = s.getPos();
+
+	const first = parseUnionTypeInner(s);
+	if (!s.is(TokenKind.Or)) {
+		return first;
+	}
+
+	const inners = [first];
+	do {
+		s.next();
+		inners.push(parseUnionTypeInner(s));
+	} while (s.is(TokenKind.Or));
+
+	return NODE('unionTypeSource', { inners }, startPos, s.getPos());
+}
+
+/**
+ * ```abnf
+ * UnionTypeTerm = FnType / NamedType
+ * ```
+*/
+function parseUnionTypeInner(s: ITokenStream): Ast.TypeSource {
+	if (s.is(TokenKind.At)) {
+		return parseFnType(s);
+	} else {
+		return parseNamedType(s);
+	}
+}
+
+/**
+ * ```abnf
+ * FnType = "@" [TypeParams] "(" ParamTypes ")" "=>" Type
+ * ParamTypes = [Type *(SEP Type)]
+ * ```
+*/
+function parseFnType(s: ITokenStream): Ast.TypeSource {
+	const startPos = s.getPos();
+
+	s.expect(TokenKind.At);
+	s.next();
+
+	let typeParams: Ast.TypeParam[];
+	if (s.is(TokenKind.Lt)) {
+		typeParams = parseTypeParams(s);
+	} else {
+		typeParams = [];
+	}
+
+	s.expect(TokenKind.OpenParen);
+	s.next();
+
+	const params: Ast.TypeSource[] = [];
+	while (!s.is(TokenKind.CloseParen)) {
+		if (params.length > 0) {
+			switch (s.getTokenKind()) {
+				case TokenKind.Comma: {
+					s.next();
+					break;
+				}
+				case TokenKind.EOF: {
+					throw new AiScriptUnexpectedEOFError(s.getPos());
+				}
+				default: {
+					throw new AiScriptSyntaxError('separator expected', s.getPos());
+				}
+			}
+		}
+		const type = parseType(s);
+		params.push(type);
+	}
+
+	s.expect(TokenKind.CloseParen);
+	s.next();
+	s.expect(TokenKind.Arrow);
+	s.next();
+
+	const resultType = parseType(s);
+
+	return NODE('fnTypeSource', { typeParams, params, result: resultType }, startPos, s.getPos());
+}
+
+/**
+ * ```abnf
+ * NamedType = IDENT ["<" Type ">"]
+ * ```
+*/
+function parseNamedType(s: ITokenStream): Ast.TypeSource {
+	const startPos = s.getPos();
+
+	let name: string;
+	if (s.is(TokenKind.Identifier)) {
+		name = s.getTokenValue();
+		s.next();
+	} else {
+		s.expect(TokenKind.NullKeyword);
+		s.next();
+		name = 'null';
+	}
+
+	// inner type
+	let inner: Ast.TypeSource | undefined;
+	if (s.is(TokenKind.Lt)) {
+		s.next();
+		inner = parseType(s);
+		s.expect(TokenKind.Gt);
+		s.next();
+	}
+
+	return NODE('namedTypeSource', { name, inner }, startPos, s.getPos());
+}
diff --git a/src/parser/token.ts b/src/parser/token.ts
index d4bdaf4..94425cd 100644
--- a/src/parser/token.ts
+++ b/src/parser/token.ts
@@ -103,6 +103,8 @@ export enum TokenKind {
 	Hat,
 	/** "{" */
 	OpenBrace,
+	/** "|" */
+	Or,
 	/** "||" */
 	Or2,
 	/** "}" */
diff --git a/src/parser/visit.ts b/src/parser/visit.ts
index efe878b..a568699 100644
--- a/src/parser/visit.ts
+++ b/src/parser/visit.ts
@@ -11,6 +11,9 @@ function visitNodeInner(node: Ast.Node, fn: (node: Ast.Node, ancestors: Ast.Node
 	// nested nodes
 	switch (result.type) {
 		case 'def': {
+			if (result.varType != null) {
+				result.varType = visitNodeInner(result.varType, fn, ancestors) as Ast.Definition['varType'];
+			}
 			result.attr = result.attr.map((attr) => visitNodeInner(attr, fn, ancestors) as Ast.Attribute);
 			result.expr = visitNodeInner(result.expr, fn, ancestors) as Ast.Definition['expr'];
 			break;
@@ -79,6 +82,12 @@ function visitNodeInner(node: Ast.Node, fn: (node: Ast.Node, ancestors: Ast.Node
 				if (param.default) {
 					param.default = visitNodeInner(param.default!, fn, ancestors) as Ast.Fn['params'][number]['default'];
 				}
+				if (param.argType != null) {
+					param.argType = visitNodeInner(param.argType, fn, ancestors) as Ast.Fn['params'][number]['argType'];
+				}
+			}
+			if (result.retType != null) {
+				result.retType = visitNodeInner(result.retType, fn, ancestors) as Ast.Fn['retType'];
 			}
 			for (let i = 0; i < result.children.length; i++) {
 				result.children[i] = visitNodeInner(result.children[i]!, fn, ancestors) as Ast.Fn['children'][number];
@@ -198,6 +207,19 @@ function visitNodeInner(node: Ast.Node, fn: (node: Ast.Node, ancestors: Ast.Node
 			)['right'];
 			break;
 		}
+
+		case 'fnTypeSource': {
+			for (let i = 0; i < result.params.length; i++) {
+				result.params[i] = visitNodeInner(result.params[i]!, fn, ancestors) as Ast.FnTypeSource['params'][number];
+			}
+			break;
+		}
+		case 'unionTypeSource': {
+			for (let i = 0; i < result.inners.length; i++) {
+				result.inners[i] = visitNodeInner(result.inners[i]!, fn, ancestors) as Ast.UnionTypeSource['inners'][number];
+			}
+			break;
+		}
 	}
 
 	ancestors.pop();
diff --git a/src/type.ts b/src/type.ts
index 92f03b4..4f2d6e6 100644
--- a/src/type.ts
+++ b/src/type.ts
@@ -47,7 +47,31 @@ export function T_FN(params: Type[], result: Type): TFn {
 	};
 }
 
-export type Type = TSimple | TGeneric | TFn;
+export type TParam = {
+	type: 'param';
+	name: string;
+}
+
+export function T_PARAM(name: string): TParam {
+	return {
+		type: 'param',
+		name,
+	};
+}
+
+export type TUnion = {
+	type: 'union';
+	inners: Type[];
+}
+
+export function T_UNION(inners: Type[]): TUnion {
+	return {
+		type: 'union',
+		inners,
+	};
+}
+
+export type Type = TSimple | TGeneric | TFn | TParam | TUnion;
 
 function assertTSimple(t: Type): asserts t is TSimple { if (t.type !== 'simple') { throw new TypeError('assertTSimple failed.'); } }
 function assertTGeneric(t: Type): asserts t is TGeneric { if (t.type !== 'generic') { throw new TypeError('assertTGeneric failed.'); } }
@@ -87,6 +111,14 @@ export function isCompatibleType(a: Type, b: Type): boolean {
 			}
 			break;
 		}
+		case 'param': {
+			// TODO
+			break;
+		}
+		case 'union': {
+			// TODO
+			break;
+		}
 	}
 
 	return true;
@@ -103,6 +135,12 @@ export function getTypeName(type: Type): string {
 		case 'fn': {
 			return `@(${type.params.map(param => getTypeName(param)).join(', ')}) { ${getTypeName(type.result)} }`;
 		}
+		case 'param': {
+			return type.name;
+		}
+		case 'union': {
+			return type.inners.join(' | ');
+		}
 	}
 }
 
@@ -121,17 +159,27 @@ export function getTypeNameBySource(typeSource: Ast.TypeSource): string {
 			const result = getTypeNameBySource(typeSource.result);
 			return `@(${params}) { ${result} }`;
 		}
+		case 'unionTypeSource': {
+			return typeSource.inners.map(inner => getTypeBySource(inner)).join(' | ');
+		}
 	}
 }
 
-export function getTypeBySource(typeSource: Ast.TypeSource): Type {
+export function getTypeBySource(typeSource: Ast.TypeSource, typeParams?: readonly Ast.TypeParam[]): Type {
 	if (typeSource.type === 'namedTypeSource') {
+		const typeParam = typeParams?.find((param) => param.name === typeSource.name);
+		if (typeParam != null) {
+			return T_PARAM(typeParam.name);
+		}
+
 		switch (typeSource.name) {
 			// simple types
 			case 'null':
 			case 'bool':
 			case 'num':
 			case 'str':
+			case 'error':
+			case 'never':
 			case 'any':
 			case 'void': {
 				if (typeSource.inner == null) {
@@ -144,7 +192,7 @@ export function getTypeBySource(typeSource: Ast.TypeSource): Type {
 			case 'obj': {
 				let innerType: Type;
 				if (typeSource.inner != null) {
-					innerType = getTypeBySource(typeSource.inner);
+					innerType = getTypeBySource(typeSource.inner, typeParams);
 				} else {
 					innerType = T_SIMPLE('any');
 				}
@@ -152,8 +200,15 @@ export function getTypeBySource(typeSource: Ast.TypeSource): Type {
 			}
 		}
 		throw new AiScriptSyntaxError(`Unknown type: '${getTypeNameBySource(typeSource)}'`, typeSource.loc.start);
+	} else if (typeSource.type === 'fnTypeSource') {
+		let fnTypeParams = typeSource.typeParams;
+		if (typeParams != null) {
+			fnTypeParams = fnTypeParams.concat(typeParams);
+		}
+		const paramTypes = typeSource.params.map(param => getTypeBySource(param, fnTypeParams));
+		return T_FN(paramTypes, getTypeBySource(typeSource.result, fnTypeParams));
 	} else {
-		const paramTypes = typeSource.params.map(param => getTypeBySource(param));
-		return T_FN(paramTypes, getTypeBySource(typeSource.result));
+		const innerTypes = typeSource.inners.map(inner => getTypeBySource(inner, typeParams));
+		return T_UNION(innerTypes);
 	}
 }
diff --git a/unreleased/obj-extract b/unreleased/obj-extract
new file mode 100644
index 0000000..1d807b8
--- /dev/null
+++ b/unreleased/obj-extract
@@ -0,0 +1,1 @@
+- 関数`Obj:pick`を追加
diff --git a/unreleased/unified-type-annotation.md b/unreleased/unified-type-annotation.md
new file mode 100644
index 0000000..480891d
--- /dev/null
+++ b/unreleased/unified-type-annotation.md
@@ -0,0 +1,5 @@
+- 以下の型注釈ができるようになりました。
+  - 関数宣言および関数型でのジェネリクス
+  - ユニオン型
+  - error型
+  - never型


Test patch:
diff --git a/test/keywords.ts b/test/keywords.ts
index ca9fca1..c318b3c 100644
--- a/test/keywords.ts
+++ b/test/keywords.ts
@@ -110,6 +110,11 @@ const sampleCodes = Object.entries<(word: string) => string>({
 	`
 	### ${word} 1
 	`,
+
+	typeParam: word =>
+	`
+	@f<${word}>(x): ${word} { x }
+	`,
 });
 
 const parser = new Parser();
diff --git a/test/newline.ts b/test/newline.ts
index 8d19501..3425d7b 100644
--- a/test/newline.ts
+++ b/test/newline.ts
@@ -95,6 +95,64 @@ describe('empty lines', () => {
 		});
     });
 
+    describe('type params', () => {
+        describe('function', () => {
+            test.concurrent('empty line before', async () => {
+                const res = await exe(`
+                @f<
+                    // comment
+                    T
+                >(v: T): T {
+                    v
+                }
+                <: f(1)
+                `);
+                eq(res, NUM(1));
+            });
+
+            test.concurrent('empty line after', async () => {
+                const res = await exe(`
+                @f<
+                    T
+                    // comment
+                >(v: T): T {
+                    v
+                }
+                <: f(1)
+                `);
+                eq(res, NUM(1));
+            });
+        });
+
+        describe('function type', () => {
+            test.concurrent('empty line before', async () => {
+                const res = await exe(`
+                let f: @<
+                    // comment
+                    T
+                >(T) => T = @(v) {
+                    v
+                }
+                <: f(1)
+                `);
+                eq(res, NUM(1));
+            });
+
+            test.concurrent('empty line after', async () => {
+                const res = await exe(`
+                let f: @<
+                    T
+                    // comment
+                >(T) => T = @(v) {
+                    v
+                }
+                <: f(1)
+                `);
+                eq(res, NUM(1));
+            });
+        });
+    });
+
     describe('function params', () => {
 		test.concurrent('empty line', async () => {
 			const res = await exe(`
diff --git a/test/std.ts b/test/std.ts
index e92309a..4588e1a 100644
--- a/test/std.ts
+++ b/test/std.ts
@@ -199,6 +199,15 @@ describe('Obj', () => {
 		`);
 		eq(res, utils.jsToVal({ a: 1, b: 3, c: 4}));
 	});
+
+	test.concurrent('pick', async () => {
+		const res = await exe(`
+		let o = { a: 1, b: 2, c: 3 }
+
+		<: Obj:pick(o, ['b', 'd'])
+		`);
+		eq(res, utils.jsToVal({ b: 2, d: null }));
+	});
 });
 
 describe('Str', () => {
diff --git a/test/types.ts b/test/types.ts
new file mode 100644
index 0000000..d876e00
--- /dev/null
+++ b/test/types.ts
@@ -0,0 +1,200 @@
+import * as assert from 'assert';
+import { describe, test } from 'vitest';
+import { utils } from '../src';
+import { NUM, STR, NULL, ARR, OBJ, BOOL, TRUE, FALSE, ERROR ,FN_NATIVE } from '../src/interpreter/value';
+import { AiScriptRuntimeError } from '../src/error';
+import { exe, getMeta, eq } from './testutils';
+
+describe('function types', () => {
+	test.concurrent('multiple params', async () => {
+		const res = await exe(`
+		let f: @(str, num) => bool = @() { true }
+		<: f('abc', 123)
+		`);
+		eq(res, TRUE);
+	});
+});
+
+describe('generics', () => {
+	describe('function', () => {
+		test.concurrent('expr', async () => {
+			const res = await exe(`
+				let f = @<T>(v: T): void {}
+				<: f("a")
+			`);
+			eq(res, NULL);
+		});
+
+		test.concurrent('consumer', async () => {
+			const res = await exe(`
+			@f<T>(v: T): void {}
+			<: f("a")
+			`);
+			eq(res, NULL);
+		});
+
+		test.concurrent('identity function', async () => {
+			const res = await exe(`
+			@f<T>(v: T): T { v }
+			<: f(1)
+			`);
+			eq(res, NUM(1));
+		});
+
+		test.concurrent('use as inner type', async () => {
+			const res = await exe(`
+			@vals<T>(v: obj<T>): arr<T> {
+				Obj:vals(v)
+			}
+			<: vals({ a: 1, b: 2, c: 3 })
+			`);
+			eq(res, ARR([NUM(1), NUM(2), NUM(3)]));
+		});
+
+		test.concurrent('use as variable type', async () => {
+			const res = await exe(`
+			@f<T>(v: T): void {
+				let v2: T = v
+			}
+			<: f(1)
+			`);
+			eq(res, NULL);
+		});
+
+		test.concurrent('use as function type', async () => {
+			const res = await exe(`
+			@f<T>(v: T): @() => T {
+				let g: @() => T = @() { v }
+				g
+			}
+			<: f(1)()
+			`);
+			eq(res, NUM(1))
+		});
+
+		test.concurrent('curried', async () => {
+			const res = await exe(`
+			@concat<A>(a: A): @<B>(B) => str {
+				@<B>(b: B) {
+					\`{a}{b}\`
+				}
+			}
+			<: concat("abc")(123)
+			`);
+			eq(res, STR('abc123'));
+		});
+
+		test.concurrent('new lines', async () => {
+			const res = await exe(`
+			@f<
+				T
+				U
+			>(x: T, y: U): arr<T | U> {
+				[x, y]
+			}
+			<: f("abc", 123)
+			`);
+			eq(res, ARR([STR('abc'), NUM(123)]));
+		});
+
+		test.concurrent('duplicate', async () => {
+			await assert.rejects(() => exe(`
+			@f<T, T>(v: T) {}
+			`));
+		});
+
+		test.concurrent('empty', async () => {
+			await assert.rejects(() => exe(`
+			@f<>() {}
+			`));
+		});
+	});
+});
+
+describe('union', () => {
+	test.concurrent('variable type', async () => {
+		const res = await exe(`
+		let a: num | null = null
+		<: a
+		`);
+		eq(res, NULL);
+	});
+
+	test.concurrent('more inners', async () => {
+		const res = await exe(`
+		let a: str | num | null = null
+		<: a
+		`);
+		eq(res, NULL);
+	});
+
+	test.concurrent('inner type', async () => {
+		const res = await exe(`
+		let a: arr<num | str> = ["abc", 123]
+		<: a
+		`);
+		eq(res, ARR([STR('abc'), NUM(123)]));
+	});
+
+	test.concurrent('param type', async () => {
+		const res = await exe(`
+		@f(x: num | str): str {
+			\`{x}\`
+		}
+		<: f(1)
+		`);
+		eq(res, STR('1'));
+	});
+
+	test.concurrent('return type', async () => {
+		const res = await exe(`
+		@f(): num | str { 1 }
+		<: f()
+		`);
+		eq(res, NUM(1));
+	});
+
+    test.concurrent('type parameter', async () => {
+        const res = await exe(`
+        @f<T>(v: T): T | null { null }
+        <: f(1)
+        `);
+        eq(res, NULL);
+    });
+
+	test.concurrent('function type', async () => {
+		const res = await exe(`
+		let f: @(num | str) => str = @(x) { \`{x}\` }
+		<: f(1)
+		`);
+		eq(res, STR('1'));
+	});
+
+	test.concurrent('invalid inner', async () => {
+		await assert.rejects(() => exe(`
+		let a: ThisIsAnInvalidTypeName | null = null
+		`));
+	});
+});
+
+describe('simple', () => {
+	test.concurrent('error', async () => {
+		const res = await exe(`
+		let a: error = Error:create("Ai")
+		<: a
+		`);
+		eq(res, ERROR('Ai'));
+	});
+
+	test.concurrent('never', async () => {
+		const res = await exe(`
+		@f() {
+			let a: never = eval {
+				return 1
+			}
+		}
+		<: f()
+		`);
+		eq(res, NUM(1));
+	});
+});