diff --git a/CommunityToolkit.Aspire.slnx b/CommunityToolkit.Aspire.slnx
index a904504fa..379592325 100644
--- a/CommunityToolkit.Aspire.slnx
+++ b/CommunityToolkit.Aspire.slnx
@@ -30,6 +30,9 @@
+
+
+
@@ -207,6 +210,7 @@
+
@@ -271,6 +275,7 @@
+
diff --git a/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/apphost.mts b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/apphost.mts
new file mode 100644
index 000000000..31b504817
--- /dev/null
+++ b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/apphost.mts
@@ -0,0 +1,19 @@
+import { mkdtempSync } from "node:fs";
+import { tmpdir } from "node:os";
+import { join } from "node:path";
+
+import { createBuilder } from "./.aspire/modules/aspire.mjs";
+
+const builder = await createBuilder();
+
+// addDbx — create a Dbx resource with an explicit name
+const dbx = await builder.addDbx({ name: "dbx" });
+
+// withHostPort — configure a fixed host port
+await dbx.withHostPort({ port: 3310 });
+
+// ---- Property access on DbxContainerResource (ExposeProperties = true) ----
+const dbxResource = await dbx;
+const _primaryEndpoint = await dbxResource.primaryEndpoint();
+
+await builder.build().run();
diff --git a/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/aspire.config.json b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/aspire.config.json
new file mode 100644
index 000000000..268adef87
--- /dev/null
+++ b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/aspire.config.json
@@ -0,0 +1,21 @@
+{
+ "appHost": {
+ "path": "apphost.mts",
+ "language": "typescript/nodejs"
+ },
+ "sdk": {
+ "version": "13.4.0"
+ },
+ "profiles": {
+ "https": {
+ "applicationUrl": "https://localhost:29750;http://localhost:28931",
+ "environmentVariables": {
+ "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:10975",
+ "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:13319"
+ }
+ }
+ },
+ "packages": {
+ "CommunityToolkit.Aspire.Hosting.Dbx": "../../../src/CommunityToolkit.Aspire.Hosting.Dbx/CommunityToolkit.Aspire.Hosting.Dbx.csproj"
+ }
+}
diff --git a/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/eslint.config.mjs b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/eslint.config.mjs
new file mode 100644
index 000000000..001a84a17
--- /dev/null
+++ b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/eslint.config.mjs
@@ -0,0 +1,17 @@
+// @ts-check
+
+import { defineConfig } from 'eslint/config';
+import tseslint from 'typescript-eslint';
+
+export default defineConfig({
+ files: ['apphost.mts'],
+ extends: [tseslint.configs.base],
+ languageOptions: {
+ parserOptions: {
+ projectService: true,
+ },
+ },
+ rules: {
+ '@typescript-eslint/no-floating-promises': ['error', { checkThenables: true }],
+ },
+});
diff --git a/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/package-lock.json b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/package-lock.json
new file mode 100644
index 000000000..1548e01cd
--- /dev/null
+++ b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/package-lock.json
@@ -0,0 +1,2044 @@
+{
+ "name": "communitytoolkit-aspire-hosting-dbx-apphost-typescript",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "communitytoolkit-aspire-hosting-dbx-apphost-typescript",
+ "version": "1.0.0",
+ "dependencies": {
+ "vscode-jsonrpc": "^8.2.0"
+ },
+ "devDependencies": {
+ "@types/node": "^22.0.0",
+ "eslint": "^10.0.3",
+ "nodemon": "^3.1.14",
+ "tsx": "^4.21.0",
+ "typescript": "^5.9.3",
+ "typescript-eslint": "^8.57.1"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz",
+ "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz",
+ "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz",
+ "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz",
+ "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz",
+ "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz",
+ "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz",
+ "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz",
+ "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz",
+ "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz",
+ "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz",
+ "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz",
+ "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz",
+ "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz",
+ "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz",
+ "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz",
+ "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz",
+ "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz",
+ "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz",
+ "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz",
+ "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz",
+ "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz",
+ "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz",
+ "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz",
+ "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz",
+ "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz",
+ "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
+ "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.12.2",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
+ "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/config-array": {
+ "version": "0.23.3",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.3.tgz",
+ "integrity": "sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/object-schema": "^3.0.3",
+ "debug": "^4.3.1",
+ "minimatch": "^10.2.4"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ }
+ },
+ "node_modules/@eslint/config-helpers": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.3.tgz",
+ "integrity": "sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^1.1.1"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ }
+ },
+ "node_modules/@eslint/core": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.1.tgz",
+ "integrity": "sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ }
+ },
+ "node_modules/@eslint/object-schema": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.3.tgz",
+ "integrity": "sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ }
+ },
+ "node_modules/@eslint/plugin-kit": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.1.tgz",
+ "integrity": "sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^1.1.1",
+ "levn": "^0.4.1"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ }
+ },
+ "node_modules/@humanfs/core": {
+ "version": "0.19.1",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+ "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/node": {
+ "version": "0.16.7",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz",
+ "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/core": "^0.19.1",
+ "@humanwhocodes/retry": "^0.4.0"
+ },
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/retry": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@types/esrecurse": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz",
+ "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "22.19.15",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.15.tgz",
+ "integrity": "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "8.57.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.2.tgz",
+ "integrity": "sha512-NZZgp0Fm2IkD+La5PR81sd+g+8oS6JwJje+aRWsDocxHkjyRw0J5L5ZTlN3LI1LlOcGL7ph3eaIUmTXMIjLk0w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.12.2",
+ "@typescript-eslint/scope-manager": "8.57.2",
+ "@typescript-eslint/type-utils": "8.57.2",
+ "@typescript-eslint/utils": "8.57.2",
+ "@typescript-eslint/visitor-keys": "8.57.2",
+ "ignore": "^7.0.5",
+ "natural-compare": "^1.4.0",
+ "ts-api-utils": "^2.4.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^8.57.2",
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
+ "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "8.57.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.2.tgz",
+ "integrity": "sha512-30ScMRHIAD33JJQkgfGW1t8CURZtjc2JpTrq5n2HFhOefbAhb7ucc7xJwdWcrEtqUIYJ73Nybpsggii6GtAHjA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "8.57.2",
+ "@typescript-eslint/types": "8.57.2",
+ "@typescript-eslint/typescript-estree": "8.57.2",
+ "@typescript-eslint/visitor-keys": "8.57.2",
+ "debug": "^4.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/project-service": {
+ "version": "8.57.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.2.tgz",
+ "integrity": "sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/tsconfig-utils": "^8.57.2",
+ "@typescript-eslint/types": "^8.57.2",
+ "debug": "^4.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "8.57.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.2.tgz",
+ "integrity": "sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.57.2",
+ "@typescript-eslint/visitor-keys": "8.57.2"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/tsconfig-utils": {
+ "version": "8.57.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.2.tgz",
+ "integrity": "sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "8.57.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.2.tgz",
+ "integrity": "sha512-Co6ZCShm6kIbAM/s+oYVpKFfW7LBc6FXoPXjTRQ449PPNBY8U0KZXuevz5IFuuUj2H9ss40atTaf9dlGLzbWZg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.57.2",
+ "@typescript-eslint/typescript-estree": "8.57.2",
+ "@typescript-eslint/utils": "8.57.2",
+ "debug": "^4.4.3",
+ "ts-api-utils": "^2.4.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "8.57.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.2.tgz",
+ "integrity": "sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "8.57.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.2.tgz",
+ "integrity": "sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/project-service": "8.57.2",
+ "@typescript-eslint/tsconfig-utils": "8.57.2",
+ "@typescript-eslint/types": "8.57.2",
+ "@typescript-eslint/visitor-keys": "8.57.2",
+ "debug": "^4.4.3",
+ "minimatch": "^10.2.2",
+ "semver": "^7.7.3",
+ "tinyglobby": "^0.2.15",
+ "ts-api-utils": "^2.4.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "8.57.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.2.tgz",
+ "integrity": "sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.9.1",
+ "@typescript-eslint/scope-manager": "8.57.2",
+ "@typescript-eslint/types": "8.57.2",
+ "@typescript-eslint/typescript-estree": "8.57.2"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "8.57.2",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.2.tgz",
+ "integrity": "sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.57.2",
+ "eslint-visitor-keys": "^5.0.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
+ "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+ "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/esbuild": {
+ "version": "0.27.4",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz",
+ "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.27.4",
+ "@esbuild/android-arm": "0.27.4",
+ "@esbuild/android-arm64": "0.27.4",
+ "@esbuild/android-x64": "0.27.4",
+ "@esbuild/darwin-arm64": "0.27.4",
+ "@esbuild/darwin-x64": "0.27.4",
+ "@esbuild/freebsd-arm64": "0.27.4",
+ "@esbuild/freebsd-x64": "0.27.4",
+ "@esbuild/linux-arm": "0.27.4",
+ "@esbuild/linux-arm64": "0.27.4",
+ "@esbuild/linux-ia32": "0.27.4",
+ "@esbuild/linux-loong64": "0.27.4",
+ "@esbuild/linux-mips64el": "0.27.4",
+ "@esbuild/linux-ppc64": "0.27.4",
+ "@esbuild/linux-riscv64": "0.27.4",
+ "@esbuild/linux-s390x": "0.27.4",
+ "@esbuild/linux-x64": "0.27.4",
+ "@esbuild/netbsd-arm64": "0.27.4",
+ "@esbuild/netbsd-x64": "0.27.4",
+ "@esbuild/openbsd-arm64": "0.27.4",
+ "@esbuild/openbsd-x64": "0.27.4",
+ "@esbuild/openharmony-arm64": "0.27.4",
+ "@esbuild/sunos-x64": "0.27.4",
+ "@esbuild/win32-arm64": "0.27.4",
+ "@esbuild/win32-ia32": "0.27.4",
+ "@esbuild/win32-x64": "0.27.4"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.1.0.tgz",
+ "integrity": "sha512-S9jlY/ELKEUwwQnqWDO+f+m6sercqOPSqXM5Go94l7DOmxHVDgmSFGWEzeE/gwgTAr0W103BWt0QLe/7mabIvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.8.0",
+ "@eslint-community/regexpp": "^4.12.2",
+ "@eslint/config-array": "^0.23.3",
+ "@eslint/config-helpers": "^0.5.3",
+ "@eslint/core": "^1.1.1",
+ "@eslint/plugin-kit": "^0.6.1",
+ "@humanfs/node": "^0.16.6",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@humanwhocodes/retry": "^0.4.2",
+ "@types/estree": "^1.0.6",
+ "ajv": "^6.14.0",
+ "cross-spawn": "^7.0.6",
+ "debug": "^4.3.2",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^9.1.2",
+ "eslint-visitor-keys": "^5.0.1",
+ "espree": "^11.2.0",
+ "esquery": "^1.7.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^8.0.0",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "minimatch": "^10.2.4",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "jiti": "*"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz",
+ "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@types/esrecurse": "^4.3.1",
+ "@types/estree": "^1.0.8",
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+ "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint/node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/espree": {
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz",
+ "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "acorn": "^8.16.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^5.0.1"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/file-entry-cache": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flat-cache": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.4"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
+ "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/get-tsconfig": {
+ "version": "4.13.6",
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz",
+ "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "resolve-pkg-maps": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/ignore-by-default": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.5"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nodemon": {
+ "version": "3.1.14",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz",
+ "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^3.5.2",
+ "debug": "^4",
+ "ignore-by-default": "^1.0.1",
+ "minimatch": "^10.2.1",
+ "pstree.remy": "^1.1.8",
+ "semver": "^7.5.3",
+ "simple-update-notifier": "^2.0.0",
+ "supports-color": "^5.5.0",
+ "touch": "^3.1.0",
+ "undefsafe": "^2.0.5"
+ },
+ "bin": {
+ "nodemon": "bin/nodemon.js"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/nodemon"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/pstree.remy": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/resolve-pkg-maps": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
+ "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/simple-update-notifier": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
+ "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.15",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/tinyglobby/node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tinyglobby/node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/touch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
+ "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "nodetouch": "bin/nodetouch.js"
+ }
+ },
+ "node_modules/ts-api-utils": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
+ "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.12"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4"
+ }
+ },
+ "node_modules/tsx": {
+ "version": "4.21.0",
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz",
+ "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "~0.27.0",
+ "get-tsconfig": "^4.7.5"
+ },
+ "bin": {
+ "tsx": "dist/cli.mjs"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ }
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/typescript-eslint": {
+ "version": "8.57.2",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.2.tgz",
+ "integrity": "sha512-VEPQ0iPgWO/sBaZOU1xo4nuNdODVOajPnTIbog2GKYr31nIlZ0fWPoCQgGfF3ETyBl1vn63F/p50Um9Z4J8O8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/eslint-plugin": "8.57.2",
+ "@typescript-eslint/parser": "8.57.2",
+ "@typescript-eslint/typescript-estree": "8.57.2",
+ "@typescript-eslint/utils": "8.57.2"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/undefsafe": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/vscode-jsonrpc": {
+ "version": "8.2.1",
+ "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.1.tgz",
+ "integrity": "sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ }
+}
diff --git a/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/package.json b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/package.json
new file mode 100644
index 000000000..c706ae39c
--- /dev/null
+++ b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "communitytoolkit-aspire-hosting-dbx-apphost-typescript",
+ "version": "1.0.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "lint": "eslint apphost.mts",
+ "predev": "npm run lint",
+ "dev": "aspire run",
+ "prebuild": "npm run lint",
+ "build": "tsc",
+ "watch": "tsc --watch"
+ },
+ "dependencies": {
+ "vscode-jsonrpc": "^8.2.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ },
+ "devDependencies": {
+ "@types/node": "^22.0.0",
+ "eslint": "^10.0.3",
+ "nodemon": "^3.1.14",
+ "tsx": "^4.21.0",
+ "typescript": "^5.9.3",
+ "typescript-eslint": "^8.57.1"
+ }
+}
diff --git a/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/tsconfig.json b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/tsconfig.json
new file mode 100644
index 000000000..c34e4c0b3
--- /dev/null
+++ b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "NodeNext",
+ "moduleResolution": "NodeNext",
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "skipLibCheck": true,
+ "outDir": "./dist",
+ "rootDir": "."
+ },
+ "include": [
+ "apphost.mts",
+ ".aspire/modules/**/*.ts"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
+}
\ No newline at end of file
diff --git a/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.csproj b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.csproj
new file mode 100644
index 000000000..dbd86e40a
--- /dev/null
+++ b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost/CommunityToolkit.Aspire.Hosting.Dbx.AppHost.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost/Program.cs b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost/Program.cs
new file mode 100644
index 000000000..c387c83c3
--- /dev/null
+++ b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost/Program.cs
@@ -0,0 +1,44 @@
+var builder = DistributedApplication.CreateBuilder(args);
+
+var postgres1 = builder.AddPostgres("postgres1")
+ .WithDbx(c => c.WithHostPort(8068));
+postgres1.AddDatabase("db1");
+postgres1.AddDatabase("db2");
+
+var postgres2 = builder.AddPostgres("postgres2")
+ .WithDbx();
+postgres2.AddDatabase("db3");
+postgres2.AddDatabase("db4");
+
+var mongodb1 = builder.AddMongoDB("mongodb1").WithDbx();
+mongodb1.AddDatabase("db5");
+mongodb1.AddDatabase("db6");
+
+var mongodb2 = builder.AddMongoDB("mongodb2").WithDbx();
+mongodb2.AddDatabase("db7");
+mongodb2.AddDatabase("db8");
+
+var redis1 = builder.AddRedis("redis1").WithDbx();
+var redis2 = builder.AddRedis("redis2").WithDbx();
+
+var sqlserver1 = builder.AddSqlServer("sqlserver1")
+ .WithDbx(c => c.WithHostPort(8068));
+sqlserver1.AddDatabase("db9");
+sqlserver1.AddDatabase("db10");
+
+var sqlserver2 = builder.AddSqlServer("sqlserver2")
+ .WithDbx();
+sqlserver2.AddDatabase("db11");
+sqlserver2.AddDatabase("db12");
+
+var mysql1 = builder.AddMySql("mysql1")
+ .WithDbx(c => c.WithHostPort(8068));
+mysql1.AddDatabase("db13");
+mysql1.AddDatabase("db14");
+
+var mysql2 = builder.AddMySql("mysql2")
+ .WithDbx();
+mysql2.AddDatabase("db15");
+mysql2.AddDatabase("db16");
+
+builder.Build().Run();
\ No newline at end of file
diff --git a/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost/Properties/launchSettings.json b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost/Properties/launchSettings.json
new file mode 100644
index 000000000..b34688d8e
--- /dev/null
+++ b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost/Properties/launchSettings.json
@@ -0,0 +1,31 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "applicationUrl": "https://localhost:17152;http://localhost:15210",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21195",
+ "ASPIRE_DASHBOARD_MCP_ENDPOINT_URL": "https://localhost:23238",
+ "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22067"
+ }
+ },
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "applicationUrl": "http://localhost:15210",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development",
+ "DOTNET_ENVIRONMENT": "Development",
+ "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19154",
+ "ASPIRE_DASHBOARD_MCP_ENDPOINT_URL": "http://localhost:18044",
+ "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20057"
+ }
+ }
+ }
+}
diff --git a/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost/appsettings.json b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost/appsettings.json
new file mode 100644
index 000000000..31c092aa4
--- /dev/null
+++ b/examples/dbx/CommunityToolkit.Aspire.Hosting.Dbx.AppHost/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning",
+ "Aspire.Hosting.Dcp": "Warning"
+ }
+ }
+}
diff --git a/examples/mongodb-ext/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.AppHost/Program.cs b/examples/mongodb-ext/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.AppHost/Program.cs
index b8abdf46c..4aa62183a 100644
--- a/examples/mongodb-ext/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.AppHost/Program.cs
+++ b/examples/mongodb-ext/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.AppHost/Program.cs
@@ -1,10 +1,14 @@
var builder = DistributedApplication.CreateBuilder(args);
-var mongodb1 = builder.AddMongoDB("mongodb1").WithDbGate(c => c.WithHostPort(8090));
+var mongodb1 = builder.AddMongoDB("mongodb1")
+ .WithDbGate(c => c.WithHostPort(8090))
+ .WithDbx(c => c.WithHostPort(9090));
mongodb1.AddDatabase("db1");
mongodb1.AddDatabase("db2");
-var mongodb2 = builder.AddMongoDB("mongodb2").WithDbGate();
+var mongodb2 = builder.AddMongoDB("mongodb2")
+ .WithDbGate()
+ .WithDbx();
mongodb2.AddDatabase("db3");
mongodb2.AddDatabase("db4");
diff --git a/examples/mysql-ext/CommunityToolkit.Aspire.Hosting.MySql.Extensions.AppHost/Program.cs b/examples/mysql-ext/CommunityToolkit.Aspire.Hosting.MySql.Extensions.AppHost/Program.cs
index 34bbcb388..58fbd8441 100644
--- a/examples/mysql-ext/CommunityToolkit.Aspire.Hosting.MySql.Extensions.AppHost/Program.cs
+++ b/examples/mysql-ext/CommunityToolkit.Aspire.Hosting.MySql.Extensions.AppHost/Program.cs
@@ -2,12 +2,14 @@
var mysql1 = builder.AddMySql("mysql1")
.WithAdminer(c => c.WithHostPort(8989))
- .WithDbGate(c => c.WithHostPort(9999));
+ .WithDbGate(c => c.WithHostPort(9999))
+ .WithDbx(c => c.WithHostPort(10999));
mysql1.AddDatabase("db1");
mysql1.AddDatabase("db2");
var mysql2 = builder.AddMySql("mysql2")
- .WithAdminer(c => c.WithHostPort(8989));
+ .WithAdminer(c => c.WithHostPort(8989))
+ .WithDbx(c => c.WithHostPort(10999));
mysql2.AddDatabase("db3");
mysql2.AddDatabase("db4");
diff --git a/examples/postgres-ext/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost/Program.cs b/examples/postgres-ext/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost/Program.cs
index b52737b26..8323caa18 100644
--- a/examples/postgres-ext/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost/Program.cs
+++ b/examples/postgres-ext/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost/Program.cs
@@ -2,13 +2,15 @@
var postgres1 = builder.AddPostgres("postgres1")
.WithDbGate(c => c.WithHostPort(8068))
- .WithAdminer(c => c.WithHostPort(8069));
+ .WithAdminer(c => c.WithHostPort(8069))
+ .WithDbx(c => c.WithHostPort(8070));
postgres1.AddDatabase("db1");
postgres1.AddDatabase("db2");
var postgres2 = builder.AddPostgres("postgres2")
.WithDbGate(c => c.WithHostPort(8068))
- .WithAdminer(c => c.WithHostPort(8069));
+ .WithAdminer(c => c.WithHostPort(8069))
+ .WithDbx(c => c.WithHostPort(8070));
postgres2.AddDatabase("db3");
postgres2.AddDatabase("db4");
diff --git a/examples/redis-ext/CommunityToolkit.Aspire.Hosting.Redis.Extensions.AppHost/Program.cs b/examples/redis-ext/CommunityToolkit.Aspire.Hosting.Redis.Extensions.AppHost/Program.cs
index d4efce3a9..6250ac1a5 100644
--- a/examples/redis-ext/CommunityToolkit.Aspire.Hosting.Redis.Extensions.AppHost/Program.cs
+++ b/examples/redis-ext/CommunityToolkit.Aspire.Hosting.Redis.Extensions.AppHost/Program.cs
@@ -1,6 +1,10 @@
var builder = DistributedApplication.CreateBuilder(args);
-builder.AddRedis("redis1").WithDbGate(c => c.WithHostPort(8068));
-builder.AddRedis("redis2").WithDbGate();
+builder.AddRedis("redis1")
+ .WithDbGate(c => c.WithHostPort(8068))
+ .WithDbx(c => c.WithHostPort(8069));
+builder.AddRedis("redis2")
+ .WithDbGate()
+ .WithDbx();
builder.Build().Run();
diff --git a/examples/sqlserver-ext/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.AppHost/Program.cs b/examples/sqlserver-ext/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.AppHost/Program.cs
index eb697ec13..4f47ea356 100644
--- a/examples/sqlserver-ext/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.AppHost/Program.cs
+++ b/examples/sqlserver-ext/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.AppHost/Program.cs
@@ -2,13 +2,15 @@
var sqlserver1 = builder.AddSqlServer("sqlserver1")
.WithDbGate(c => c.WithHostPort(8068))
- .WithAdminer(c => c.WithHostPort(8069));
+ .WithAdminer(c => c.WithHostPort(8069))
+ .WithDbx(c => c.WithHostPort(8070));
sqlserver1.AddDatabase("db1");
sqlserver1.AddDatabase("db2");
var sqlserver2 = builder.AddSqlServer("sqlserver2")
.WithDbGate()
- .WithAdminer();
+ .WithAdminer()
+ .WithDbx();
sqlserver2.AddDatabase("db3");
sqlserver2.AddDatabase("db4");
diff --git a/src/CommunityToolkit.Aspire.Hosting.Dbx/CommunityToolkit.Aspire.Hosting.Dbx.csproj b/src/CommunityToolkit.Aspire.Hosting.Dbx/CommunityToolkit.Aspire.Hosting.Dbx.csproj
new file mode 100644
index 000000000..3997fba8a
--- /dev/null
+++ b/src/CommunityToolkit.Aspire.Hosting.Dbx/CommunityToolkit.Aspire.Hosting.Dbx.csproj
@@ -0,0 +1,12 @@
+
+
+
+ hosting dbx
+ An Aspire integration for dbx hosting.
+
+
+
+
+
+
+
diff --git a/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxBuilderExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxBuilderExtensions.cs
new file mode 100644
index 000000000..f7f913208
--- /dev/null
+++ b/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxBuilderExtensions.cs
@@ -0,0 +1,99 @@
+using Aspire.Hosting.ApplicationModel;
+using System.Text.Json;
+
+#pragma warning disable ASPIREATS001 // AspireExport is experimental
+
+namespace Aspire.Hosting;
+
+///
+/// Provides extension methods for dbx resources to an .
+///
+public static class DbxBuilderExtensions
+{
+ private const string DBX_STATIC_DIR = "/app/static";
+ private const string DBX_DATA_DIR = "/app/data";
+
+ ///
+ /// Configures the host port that the dbx resource is exposed on instead of using randomly assigned port.
+ ///
+ /// The resource builder for dbx.
+ /// The port to bind on the host. If is used random port will be assigned.
+ /// The resource builder for dbx.
+ [AspireExport]
+ public static IResourceBuilder WithHostPort(this IResourceBuilder builder, int? port)
+ {
+ ArgumentNullException.ThrowIfNull(builder);
+
+ return builder.WithEndpoint(DbxContainerResource.PrimaryEndpointName, endpoint =>
+ {
+ endpoint.Port = port;
+ });
+ }
+
+ ///
+ /// Adds a dbx container resource to the application.
+ ///
+ /// The resource builder.
+ /// The name of the resource. This name will be used as the connection string name when referenced in a dependency. Optional; defaults to dbx.
+ /// The host port to bind the underlying container to.
+ ///
+ /// Multiple calls will return the same resource builder instance.
+ ///
+ /// A reference to the .
+ [AspireExport]
+ public static IResourceBuilder AddDbx(this IDistributedApplicationBuilder builder, [ResourceName] string name = "dbx", int? port = null)
+ {
+ ArgumentNullException.ThrowIfNull(builder);
+ ArgumentNullException.ThrowIfNull(name);
+
+ if (builder.Resources.OfType().SingleOrDefault() is { } existingDbxResource)
+ {
+ var builderForExistingResource = builder.CreateResourceBuilder(existingDbxResource);
+ return builderForExistingResource;
+ }
+
+ var dbxContainer = new DbxContainerResource(name);
+ var dbxContainerBuilder = builder.AddResource(dbxContainer)
+ .WithImage(DbxContainerImageTags.Image, DbxContainerImageTags.Tag)
+ .WithImageRegistry(DbxContainerImageTags.Registry)
+ .WithHttpEndpoint(targetPort: 4224, port: port, name: DbxContainerResource.PrimaryEndpointName)
+ .WithUrlForEndpoint(DbxContainerResource.PrimaryEndpointName, e => e.DisplayText = "dbx Dashboard")
+ .WithIconName("WindowDatabase")
+ .ExcludeFromManifest();
+
+ dbxContainerBuilder.WithContainerFiles(
+ destinationPath: DBX_DATA_DIR,
+ callback: (context, _) =>
+ {
+ var options = new JsonSerializerOptions
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.KebabCaseLower
+ };
+ var connectionsContents = JsonSerializer.Serialize(dbxContainer.Connections, options);
+
+ var secrets = dbxContainer.Connections
+ .ToDictionary(connection => $"connection:{connection.Id}:password", connection => connection.Password);
+ var secretsContents = JsonSerializer.Serialize(secrets);
+
+ IEnumerable files = [
+ new ContainerFile
+ {
+ Contents = connectionsContents,
+ Name = "connections.json",
+ },
+ new ContainerFile
+ {
+ Contents = secretsContents,
+ Name = "secrets.json",
+ }
+ ];
+
+ return Task.FromResult(files);
+ }
+ );
+
+ return dbxContainerBuilder;
+ }
+}
+
+#pragma warning restore ASPIREATS001
diff --git a/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxConnectionConfig.cs b/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxConnectionConfig.cs
new file mode 100644
index 000000000..3c54e70c2
--- /dev/null
+++ b/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxConnectionConfig.cs
@@ -0,0 +1,108 @@
+using System.Text.Json.Serialization;
+
+namespace Aspire.Hosting.ApplicationModel;
+
+///
+/// Represents a database connection configuration for dbx.
+///
+public sealed class DbxConnectionConfig
+{
+ /// Gets or sets the unique identifier for the connection.
+ [JsonPropertyName("id")]
+ public required string Id { get; set; }
+
+ /// Gets or sets the display name of the connection.
+ [JsonPropertyName("name")]
+ public required string Name { get; set; }
+
+ /// Gets or sets the database type.
+ [JsonPropertyName("db_type")]
+ public required DbxDatabaseType DbType { get; set; }
+
+ /// Gets or sets optional URL parameters.
+ [JsonPropertyName("url_params")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? UrlParams { get; set; }
+
+ /// Gets or sets the host address.
+ [JsonPropertyName("host")]
+ public required string Host { get; set; }
+
+ /// Gets or sets the port number.
+ [JsonPropertyName("port")]
+ public required ushort Port { get; set; }
+
+ /// Gets or sets the username for authentication.
+ [JsonPropertyName("username")]
+ public required string Username { get; set; }
+
+ /// Gets or sets the password for authentication.
+ [JsonPropertyName("password")]
+ public required string Password { get; set; }
+
+ /// Gets or sets the database name.
+ [JsonPropertyName("database")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Database { get; set; }
+
+ /// Gets or sets the connection timeout in seconds.
+ [JsonPropertyName("connect_timeout_secs")]
+ public ulong ConnectTimeoutSecs { get; set; } = 30;
+
+ /// Gets or sets the query timeout in seconds.
+ [JsonPropertyName("query_timeout_secs")]
+ public ulong QueryTimeoutSecs { get; set; } = 30;
+
+ /// Gets or sets whether SSL is enabled.
+ [JsonPropertyName("ssl")]
+ public bool Ssl { get; set; }
+
+ /// Gets or sets an explicit connection string, overriding individual fields.
+ [JsonPropertyName("connection_string")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? ConnectionString { get; set; }
+
+ /// Gets or sets the Redis connection mode (e.g. "standalone", "sentinel", "cluster").
+ [JsonPropertyName("redis_connection_mode")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? RedisConnectionMode { get; set; }
+
+ /// Gets or sets the Redis Sentinel master name.
+ [JsonPropertyName("redis_sentinel_master")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? RedisSentinelMaster { get; set; }
+
+ /// Gets or sets the Redis Sentinel nodes (comma-separated).
+ [JsonPropertyName("redis_sentinel_nodes")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? RedisSentinelNodes { get; set; }
+
+ /// Gets or sets the Redis Sentinel username.
+ [JsonPropertyName("redis_sentinel_username")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? RedisSentinelUsername { get; set; }
+
+ /// Gets or sets the Redis Sentinel password.
+ [JsonPropertyName("redis_sentinel_password")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? RedisSentinelPassword { get; set; }
+
+ /// Gets or sets whether TLS is enabled for Redis Sentinel.
+ [JsonPropertyName("redis_sentinel_tls")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
+ public bool RedisSentinelTls { get; set; }
+
+ /// Gets or sets the Redis cluster nodes (comma-separated).
+ [JsonPropertyName("redis_cluster_nodes")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? RedisClusterNodes { get; set; }
+
+ /// Gets or sets the JDBC driver class.
+ [JsonPropertyName("jdbc_driver_class")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? JdbcDriverClass { get; set; }
+
+ /// Gets or sets the JDBC driver paths.
+ [JsonPropertyName("jdbc_driver_paths")]
+ public List JdbcDriverPaths { get; set; } = [];
+}
diff --git a/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxContainerImageTags.cs b/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxContainerImageTags.cs
new file mode 100644
index 000000000..741d94bf3
--- /dev/null
+++ b/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxContainerImageTags.cs
@@ -0,0 +1,10 @@
+internal static class DbxContainerImageTags
+{
+ /// docker.io
+ public const string Registry = "docker.io";
+ /// library/adminer
+ public const string Image = "t8y2/dbx";
+ /// 0.5.29
+ public const string Tag = "0.5.29";
+}
+
diff --git a/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxContainerResource.cs b/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxContainerResource.cs
new file mode 100644
index 000000000..e72e8a31f
--- /dev/null
+++ b/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxContainerResource.cs
@@ -0,0 +1,40 @@
+#pragma warning disable ASPIREATS001 // AspireExport is experimental
+
+namespace Aspire.Hosting.ApplicationModel;
+
+///
+/// Represents a container resource for dbx.
+///
+/// The name of the container resource.
+[AspireExport(ExposeProperties = true)]
+public sealed class DbxContainerResource(string name) : ContainerResource(name)
+{
+ internal const string PrimaryEndpointName = "http";
+
+ private EndpointReference? _primaryEndpoint;
+
+ ///
+ /// Gets the primary endpoint for the dbx resource.
+ ///
+ public EndpointReference PrimaryEndpoint => _primaryEndpoint ??= new(this, PrimaryEndpointName);
+
+ internal ICollection Connections { get; set; } = new List();
+
+ ///
+ /// Adds a new connection to the dbx container resource.
+ ///
+ /// The connection to add
+ /// Returns false if the connection was already added.
+ public bool AddConnection(DbxConnectionConfig connection)
+ {
+ if (Connections.Any(c => c.Id == connection.Id))
+ {
+ return false;
+ }
+
+ Connections.Add(connection);
+ return true;
+ }
+}
+
+#pragma warning restore ASPIREATS001
diff --git a/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxDatabaseType.cs b/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxDatabaseType.cs
new file mode 100644
index 000000000..be2c0d90d
--- /dev/null
+++ b/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxDatabaseType.cs
@@ -0,0 +1,191 @@
+using CommunityToolkit.Aspire.Hosting.Dbx;
+using System.Text.Json.Serialization;
+
+namespace Aspire.Hosting.ApplicationModel;
+
+///
+/// Represents the type of database for a dbx connection.
+///
+[JsonConverter(typeof(DbxDatabaseTypeJsonConverter))]
+public enum DbxDatabaseType
+{
+ /// MySQL database.
+ [JsonPropertyName("mysql")]
+ Mysql,
+
+ /// PostgreSQL database.
+ [JsonPropertyName("postgres")]
+ Postgres,
+
+ /// SQLite database.
+ [JsonPropertyName("sqlite")]
+ Sqlite,
+
+ /// Redis key-value store.
+ [JsonPropertyName("redis")]
+ Redis,
+
+ /// DuckDB analytical database.
+ [JsonPropertyName("duckdb")]
+ DuckDb,
+
+ /// ClickHouse columnar database.
+ [JsonPropertyName("clickhouse")]
+ ClickHouse,
+
+ /// Microsoft SQL Server database.
+ [JsonPropertyName("sqlserver")]
+ SqlServer,
+
+ /// MongoDB document database.
+ [JsonPropertyName("mongodb")]
+ MongoDb,
+
+ /// Oracle database.
+ [JsonPropertyName("oracle")]
+ Oracle,
+
+ /// Elasticsearch search engine.
+ [JsonPropertyName("elasticsearch")]
+ Elasticsearch,
+
+ /// Apache Doris analytical database.
+ [JsonPropertyName("doris")]
+ Doris,
+
+ /// StarRocks analytical database.
+ [JsonPropertyName("starrocks")]
+ StarRocks,
+
+ /// Amazon Redshift data warehouse.
+ [JsonPropertyName("redshift")]
+ Redshift,
+
+ /// Dameng database.
+ [JsonPropertyName("dameng")]
+ Dameng,
+
+ /// Kingbase database.
+ [JsonPropertyName("kingbase")]
+ Kingbase,
+
+ /// HighGo database.
+ [JsonPropertyName("highgo")]
+ Highgo,
+
+ /// VastBase database.
+ [JsonPropertyName("vastbase")]
+ Vastbase,
+
+ /// GoldenDB database.
+ [JsonPropertyName("goldendb")]
+ Goldendb,
+
+ /// GaussDB database.
+ [JsonPropertyName("gaussdb")]
+ Gaussdb,
+
+ /// YashanDB database.
+ [JsonPropertyName("yashandb")]
+ Yashandb,
+
+ /// Databricks lakehouse platform.
+ [JsonPropertyName("databricks")]
+ Databricks,
+
+ /// SAP HANA in-memory database.
+ [JsonPropertyName("saphana")]
+ SapHana,
+
+ /// Teradata data warehouse.
+ [JsonPropertyName("teradata")]
+ Teradata,
+
+ /// Vertica analytical database.
+ [JsonPropertyName("vertica")]
+ Vertica,
+
+ /// Firebird relational database.
+ [JsonPropertyName("firebird")]
+ Firebird,
+
+ /// Exasol analytical database.
+ [JsonPropertyName("exasol")]
+ Exasol,
+
+ /// openGauss database.
+ [JsonPropertyName("opengauss")]
+ OpenGauss,
+
+ /// OceanBase Oracle-compatible database.
+ [JsonPropertyName("oceanbase-oracle")]
+ OceanbaseOracle,
+
+ /// GBase database.
+ [JsonPropertyName("gbase")]
+ Gbase,
+
+ /// Microsoft Access database.
+ [JsonPropertyName("access")]
+ Access,
+
+ /// H2 embedded database.
+ [JsonPropertyName("h2")]
+ H2,
+
+ /// Snowflake cloud data warehouse.
+ [JsonPropertyName("snowflake")]
+ Snowflake,
+
+ /// Trino distributed query engine.
+ [JsonPropertyName("trino")]
+ Trino,
+
+ /// Apache Hive data warehouse.
+ [JsonPropertyName("hive")]
+ Hive,
+
+ /// IBM Db2 database.
+ [JsonPropertyName("db2")]
+ Db2,
+
+ /// IBM Informix database.
+ [JsonPropertyName("informix")]
+ Informix,
+
+ /// Neo4j graph database.
+ [JsonPropertyName("neo4j")]
+ Neo4j,
+
+ /// Apache Cassandra NoSQL database.
+ [JsonPropertyName("cassandra")]
+ Cassandra,
+
+ /// Google BigQuery data warehouse.
+ [JsonPropertyName("bigquery")]
+ Bigquery,
+
+ /// Apache Kylin OLAP engine.
+ [JsonPropertyName("kylin")]
+ Kylin,
+
+ /// SunDB database.
+ [JsonPropertyName("sundb")]
+ Sundb,
+
+ /// TDengine time-series database.
+ [JsonPropertyName("tdengine")]
+ Tdengine,
+
+ /// Xugu database.
+ [JsonPropertyName("xugu")]
+ Xugu,
+
+ /// InterSystems IRIS data platform.
+ [JsonPropertyName("iris")]
+ Iris,
+
+ /// Generic JDBC connection.
+ [JsonPropertyName("jdbc")]
+ Jdbc,
+}
diff --git a/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxDatabaseTypeJsonConverter.cs b/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxDatabaseTypeJsonConverter.cs
new file mode 100644
index 000000000..51869e9dd
--- /dev/null
+++ b/src/CommunityToolkit.Aspire.Hosting.Dbx/DbxDatabaseTypeJsonConverter.cs
@@ -0,0 +1,51 @@
+using Aspire.Hosting.ApplicationModel;
+using System.Reflection;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace CommunityToolkit.Aspire.Hosting.Dbx;
+
+///
+/// JSON converter for that respects on each enum member.
+///
+internal sealed class DbxDatabaseTypeJsonConverter : JsonConverter
+{
+ private static readonly Dictionary s_readMap;
+ private static readonly Dictionary s_writeMap;
+
+ static DbxDatabaseTypeJsonConverter()
+ {
+ var fields = typeof(DbxDatabaseType).GetFields(BindingFlags.Public | BindingFlags.Static);
+
+ s_readMap = new Dictionary(fields.Length, StringComparer.OrdinalIgnoreCase);
+ s_writeMap = new Dictionary(fields.Length);
+
+ foreach (var field in fields)
+ {
+ var value = (DbxDatabaseType)field.GetValue(null)!;
+ var jsonName = field.GetCustomAttribute()?.Name ?? field.Name;
+
+ s_readMap[jsonName] = value;
+ s_writeMap[value] = jsonName;
+ }
+ }
+
+ ///
+ public override DbxDatabaseType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ var raw = reader.GetString() ?? throw new JsonException("Expected a string value for DbxDatabaseType.");
+
+ if (s_readMap.TryGetValue(raw, out var result))
+ {
+ return result;
+ }
+
+ throw new JsonException($"Unknown DbxDatabaseType value: '{raw}'.");
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, DbxDatabaseType value, JsonSerializerOptions options)
+ {
+ writer.WriteStringValue(s_writeMap[value]);
+ }
+}
diff --git a/src/CommunityToolkit.Aspire.Hosting.Dbx/README.md b/src/CommunityToolkit.Aspire.Hosting.Dbx/README.md
new file mode 100644
index 000000000..0376466b7
--- /dev/null
+++ b/src/CommunityToolkit.Aspire.Hosting.Dbx/README.md
@@ -0,0 +1 @@
+This package is designed to be used internally by the community toolkit and is not intended to be used directly in the application code.
diff --git a/src/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.csproj b/src/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.csproj
index 692c9a91a..3e6f94ae4 100644
--- a/src/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.csproj
+++ b/src/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.csproj
@@ -14,6 +14,7 @@
+
diff --git a/src/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions/MongoDBBuilderExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions/MongoDBBuilderExtensions.cs
index cd39e4e3c..15b33c40a 100644
--- a/src/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions/MongoDBBuilderExtensions.cs
+++ b/src/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions/MongoDBBuilderExtensions.cs
@@ -69,6 +69,68 @@ internal static IResourceBuilder WithDbGateForPolyglot(th
return builder.WithDbGate(configureContainer: null, containerName);
}
#pragma warning restore ASPIREATS001
+
+
+ ///
+ /// Adds an administration and development platform for MongoDB to the application model using dbx.
+ ///
+ ///
+ /// This version of the package defaults to the tag of the container image.
+ /// This overload is not available in polyglot app hosts. Use instead.
+ ///
+ /// The MongoDB server resource builder.
+ /// Configuration callback for dbx container resource.
+ /// The name of the container (Optional).
+ ///
+ /// Use in application host with a MongoDB resource
+ ///
+ /// var builder = DistributedApplication.CreateBuilder(args);
+ ///
+ /// var mongodb = builder.AddMongoDB("mongodb")
+ /// .WithDbx();
+ /// var db = mongodb.AddDatabase("db");
+ ///
+ /// var api = builder.AddProject<Projects.Api>("api")
+ /// .WithReference(db);
+ ///
+ /// builder.Build().Run();
+ ///
+ ///
+ /// A reference to the .
+ [AspireExportIgnore(Reason = "Action> is not supported reliably in polyglot app hosts. Use the container options overload instead.")]
+ public static IResourceBuilder WithDbx(this IResourceBuilder builder, Action>? configureContainer = null, string? containerName = null)
+ {
+ ArgumentNullException.ThrowIfNull(builder);
+
+ containerName ??= "dbx";
+ var dbxBuilder = DbxBuilderExtensions.AddDbx(builder.ApplicationBuilder, containerName);
+
+ dbxBuilder
+ .WithEnvironment(context => ConfigureDbxContainer(context, dbxBuilder, builder));
+
+ configureContainer?.Invoke(dbxBuilder);
+
+ return builder;
+ }
+
+ ///
+ /// Adds an administration and development platform for MongoDB to the application model using dbx.
+ ///
+ /// The MongoDB server resource builder.
+ /// The name of the container (Optional).
+ /// Optional image tag override for the dbx container.
+ /// A reference to the .
+ [AspireExport]
+ internal static IResourceBuilder WithDbx(this IResourceBuilder builder, string? containerName = null, string? imageTag = null)
+ {
+ Action>? configureContainer = null;
+ if (!string.IsNullOrWhiteSpace(imageTag))
+ {
+ configureContainer = dbxBuilder => dbxBuilder.WithImageTag(imageTag);
+ }
+
+ return WithDbx(builder, configureContainer, containerName);
+ }
private static void ConfigureDbGateContainer(EnvironmentCallbackContext context, IResourceBuilder builder)
{
@@ -99,4 +161,28 @@ private static void ConfigureDbGateContainer(EnvironmentCallbackContext context,
context.EnvironmentVariables["CONNECTIONS"] = connectionId;
}
}
+
+ private static async Task ConfigureDbxContainer(
+ EnvironmentCallbackContext context,
+ IResourceBuilder dbxBuilder,
+ IResourceBuilder builder
+ )
+ {
+ var mongoDbServerResource = builder.Resource;
+
+ dbxBuilder.Resource.AddConnection(
+ new DbxConnectionConfig
+ {
+ Id = mongoDbServerResource.Name,
+ Name = mongoDbServerResource.Name,
+ DbType = DbxDatabaseType.MongoDb,
+ Host = mongoDbServerResource.Name,
+ Port = ushort.Parse(mongoDbServerResource.PrimaryEndpoint.TargetPort!.Value.ToString()),
+ Username = await mongoDbServerResource.UserNameReference.GetValueAsync(context.CancellationToken) ?? string.Empty,
+ Password = mongoDbServerResource.PasswordParameter is not null
+ ? await mongoDbServerResource.PasswordParameter.GetValueAsync(context.CancellationToken) ?? string.Empty
+ : string.Empty,
+ }
+ );
+ }
}
diff --git a/src/CommunityToolkit.Aspire.Hosting.MySql.Extensions/CommunityToolkit.Aspire.Hosting.MySql.Extensions.csproj b/src/CommunityToolkit.Aspire.Hosting.MySql.Extensions/CommunityToolkit.Aspire.Hosting.MySql.Extensions.csproj
index 702df857a..fc2782d25 100644
--- a/src/CommunityToolkit.Aspire.Hosting.MySql.Extensions/CommunityToolkit.Aspire.Hosting.MySql.Extensions.csproj
+++ b/src/CommunityToolkit.Aspire.Hosting.MySql.Extensions/CommunityToolkit.Aspire.Hosting.MySql.Extensions.csproj
@@ -14,6 +14,7 @@
+
diff --git a/src/CommunityToolkit.Aspire.Hosting.MySql.Extensions/MySqlBuilderExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.MySql.Extensions/MySqlBuilderExtensions.cs
index f9ec0794a..0faa5a42a 100644
--- a/src/CommunityToolkit.Aspire.Hosting.MySql.Extensions/MySqlBuilderExtensions.cs
+++ b/src/CommunityToolkit.Aspire.Hosting.MySql.Extensions/MySqlBuilderExtensions.cs
@@ -93,6 +93,67 @@ public static IResourceBuilder WithDbGate(this IResourceBui
return builder;
}
+
+ ///
+ /// Adds an administration and development platform for MySql to the application model using dbx.
+ ///
+ ///
+ /// This version of the package defaults to the tag of the container image.
+ /// This overload is not available in polyglot app hosts. Use instead.
+ ///
+ /// The MySql server resource builder.
+ /// Configuration callback for dbx container resource.
+ /// The name of the container (Optional).
+ ///
+ /// Use in application host with a MySql resource
+ ///
+ /// var builder = DistributedApplication.CreateBuilder(args);
+ ///
+ /// var mysql = builder.AddMySql("mysql")
+ /// .WithDbx();
+ /// var db = mysql.AddDatabase("db");
+ ///
+ /// var api = builder.AddProject<Projects.Api>("api")
+ /// .WithReference(db);
+ ///
+ /// builder.Build().Run();
+ ///
+ ///
+ /// A reference to the .
+ [AspireExportIgnore(Reason = "Action> is not supported reliably in polyglot app hosts. Use the container options overload instead.")]
+ public static IResourceBuilder WithDbx(this IResourceBuilder builder, Action>? configureContainer = null, string? containerName = null)
+ {
+ ArgumentNullException.ThrowIfNull(builder);
+
+ containerName ??= "dbx";
+ var dbxBuilder = DbxBuilderExtensions.AddDbx(builder.ApplicationBuilder, containerName);
+
+ dbxBuilder
+ .WithEnvironment(context => ConfigureDbxContainer(context, dbxBuilder, builder));
+
+ configureContainer?.Invoke(dbxBuilder);
+
+ return builder;
+ }
+
+ ///
+ /// Adds an administration and development platform for MySql to the application model using dbx.
+ ///
+ /// The MySql server resource builder.
+ /// The name of the container (Optional).
+ /// Optional image tag override for the dbx container.
+ /// A reference to the .
+ [AspireExport]
+ internal static IResourceBuilder WithDbx(this IResourceBuilder builder, string? containerName = null, string? imageTag = null)
+ {
+ Action>? configureContainer = null;
+ if (!string.IsNullOrWhiteSpace(imageTag))
+ {
+ configureContainer = dbxBuilder => dbxBuilder.WithImageTag(imageTag);
+ }
+
+ return WithDbx(builder, configureContainer, containerName);
+ }
private static void ConfigureDbGateContainer(EnvironmentCallbackContext context, IResourceBuilder builder)
{
@@ -161,4 +222,26 @@ internal static async Task ConfigureAdminerContainer(EnvironmentCallbackContext
string servers_json = JsonSerializer.Serialize(servers);
context.EnvironmentVariables["ADMINER_SERVERS"] = servers_json;
}
+
+ private static async Task ConfigureDbxContainer(
+ EnvironmentCallbackContext context,
+ IResourceBuilder dbxBuilder,
+ IResourceBuilder builder
+ )
+ {
+ var mySqlServerResource = builder.Resource;
+
+ dbxBuilder.Resource.AddConnection(
+ new DbxConnectionConfig
+ {
+ Id = mySqlServerResource.Name,
+ Name = mySqlServerResource.Name,
+ DbType = DbxDatabaseType.Mysql,
+ Host = mySqlServerResource.Name,
+ Port = ushort.Parse(mySqlServerResource.PrimaryEndpoint.TargetPort!.Value.ToString()),
+ Username = "root",
+ Password = await mySqlServerResource.PasswordParameter.GetValueAsync(context.CancellationToken) ?? string.Empty,
+ }
+ );
+ }
}
diff --git a/src/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.csproj b/src/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.csproj
index 0e6508a00..6f679b7aa 100644
--- a/src/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.csproj
+++ b/src/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.csproj
@@ -13,6 +13,7 @@
+
diff --git a/src/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/PostgresBuilderExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/PostgresBuilderExtensions.cs
index 2b58d1660..9666a07be 100644
--- a/src/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/PostgresBuilderExtensions.cs
+++ b/src/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/PostgresBuilderExtensions.cs
@@ -1,7 +1,5 @@
using Aspire.Hosting.ApplicationModel;
-using System.Text;
using System.Text.Json;
-using System.Text.Json.Serialization;
#pragma warning disable ASPIREATS001
@@ -106,6 +104,67 @@ public static IResourceBuilder WithAdminer(this IResourc
internal static IResourceBuilder WithAdminerForPolyglot(this IResourceBuilder builder, string? containerName = null) =>
builder.WithAdminer(configureContainer: null, containerName);
+ ///
+ /// Adds an administration and development platform for PostgreSQL to the application model using dbx.
+ ///
+ ///
+ /// This version of the package defaults to the tag of the container image.
+ /// This overload is not available in polyglot app hosts. Use instead.
+ ///
+ /// The Postgres server resource builder.
+ /// Configuration callback for dbx container resource.
+ /// The name of the container (Optional).
+ ///
+ /// Use in application host with a Postgres resource
+ ///
+ /// var builder = DistributedApplication.CreateBuilder(args);
+ ///
+ /// var postgres = builder.AddPostgres("postgres")
+ /// .WithDbx();
+ /// var db = postgres.AddDatabase("db");
+ ///
+ /// var api = builder.AddProject<Projects.Api>("api")
+ /// .WithReference(db);
+ ///
+ /// builder.Build().Run();
+ ///
+ ///
+ /// A reference to the .
+ [AspireExportIgnore(Reason = "Action> is not supported reliably in polyglot app hosts. Use the container options overload instead.")]
+ public static IResourceBuilder WithDbx(this IResourceBuilder builder, Action>? configureContainer = null, string? containerName = null)
+ {
+ ArgumentNullException.ThrowIfNull(builder);
+
+ containerName ??= "dbx";
+ var dbxBuilder = DbxBuilderExtensions.AddDbx(builder.ApplicationBuilder, containerName);
+
+ dbxBuilder
+ .WithEnvironment(context => ConfigureDbxContainer(context, dbxBuilder, builder));
+
+ configureContainer?.Invoke(dbxBuilder);
+
+ return builder;
+ }
+
+ ///
+ /// Adds an administration and development platform for PostgreSQL to the application model using dbx.
+ ///
+ /// The Postgres server resource builder.
+ /// The name of the container (Optional).
+ /// Optional image tag override for the dbx container.
+ /// A reference to the .
+ [AspireExport]
+ internal static IResourceBuilder WithDbx(this IResourceBuilder builder, string? containerName = null, string? imageTag = null)
+ {
+ Action>? configureContainer = null;
+ if (!string.IsNullOrWhiteSpace(imageTag))
+ {
+ configureContainer = dbxBuilder => dbxBuilder.WithImageTag(imageTag);
+ }
+
+ return WithDbx(builder, configureContainer, containerName);
+ }
+
private static void ConfigureDbGateContainer(EnvironmentCallbackContext context, IResourceBuilder builder)
{
var postgresServer = builder.Resource;
@@ -185,6 +244,28 @@ internal static async Task ConfigureAdminerContainer(EnvironmentCallbackContext
context.EnvironmentVariables["ADMINER_SERVERS"] = servers_json;
}
+
+ private static async Task ConfigureDbxContainer(
+ EnvironmentCallbackContext context,
+ IResourceBuilder dbxBuilder,
+ IResourceBuilder builder
+ )
+ {
+ var postgresServerResource = builder.Resource;
+
+ dbxBuilder.Resource.AddConnection(
+ new DbxConnectionConfig
+ {
+ Id = postgresServerResource.Name,
+ Name = postgresServerResource.Name,
+ DbType = DbxDatabaseType.Postgres,
+ Host = postgresServerResource.Name,
+ Port = ushort.Parse(postgresServerResource.PrimaryEndpoint.TargetPort!.Value.ToString()),
+ Username = await postgresServerResource.UserNameReference.GetValueAsync(context.CancellationToken) ?? string.Empty,
+ Password = await postgresServerResource.PasswordParameter.GetValueAsync(context.CancellationToken) ?? string.Empty,
+ }
+ );
+ }
}
#pragma warning restore ASPIREATS001
diff --git a/src/CommunityToolkit.Aspire.Hosting.Redis.Extensions/CommunityToolkit.Aspire.Hosting.Redis.Extensions.csproj b/src/CommunityToolkit.Aspire.Hosting.Redis.Extensions/CommunityToolkit.Aspire.Hosting.Redis.Extensions.csproj
index e59332bd3..8cc2b4cbc 100644
--- a/src/CommunityToolkit.Aspire.Hosting.Redis.Extensions/CommunityToolkit.Aspire.Hosting.Redis.Extensions.csproj
+++ b/src/CommunityToolkit.Aspire.Hosting.Redis.Extensions/CommunityToolkit.Aspire.Hosting.Redis.Extensions.csproj
@@ -12,6 +12,7 @@
+
diff --git a/src/CommunityToolkit.Aspire.Hosting.Redis.Extensions/RedisBuilderExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.Redis.Extensions/RedisBuilderExtensions.cs
index a595b404d..6b20005cd 100644
--- a/src/CommunityToolkit.Aspire.Hosting.Redis.Extensions/RedisBuilderExtensions.cs
+++ b/src/CommunityToolkit.Aspire.Hosting.Redis.Extensions/RedisBuilderExtensions.cs
@@ -51,6 +51,66 @@ public static IResourceBuilder WithDbGate(this IResourceBuilder
+ /// Adds an administration and development platform for Redis to the application model using dbx.
+ ///
+ ///
+ /// This version of the package defaults to the tag of the container image.
+ /// This overload is not available in polyglot app hosts. Use instead.
+ ///
+ /// The Redis server resource builder.
+ /// Configuration callback for dbx container resource.
+ /// The name of the container (Optional).
+ ///
+ /// Use in application host with a Postgres resource
+ ///
+ /// var builder = DistributedApplication.CreateBuilder(args);
+ ///
+ /// var redis = builder.AddRedis("redis")
+ /// .WithDbx();
+ ///
+ /// var api = builder.AddProject<Projects.Api>("api")
+ /// .WithReference(redis);
+ ///
+ /// builder.Build().Run();
+ ///
+ ///
+ /// A reference to the .
+ [AspireExportIgnore(Reason = "Action> is not supported reliably in polyglot app hosts. Use the container options overload instead.")]
+ public static IResourceBuilder WithDbx(this IResourceBuilder builder, Action>? configureContainer = null, string? containerName = null)
+ {
+ ArgumentNullException.ThrowIfNull(builder);
+
+ containerName ??= "dbx";
+ var dbxBuilder = DbxBuilderExtensions.AddDbx(builder.ApplicationBuilder, containerName);
+
+ dbxBuilder
+ .WithEnvironment(context => ConfigureDbxContainer(context, dbxBuilder, builder));
+
+ configureContainer?.Invoke(dbxBuilder);
+
+ return builder;
+ }
+
+ ///
+ /// Adds an administration and development platform for Redis to the application model using dbx.
+ ///
+ /// The Redis server resource builder.
+ /// The name of the container (Optional).
+ /// Optional image tag override for the dbx container.
+ /// A reference to the .
+ [AspireExport]
+ internal static IResourceBuilder WithDbx(this IResourceBuilder builder, string? containerName = null, string? imageTag = null)
+ {
+ Action>? configureContainer = null;
+ if (!string.IsNullOrWhiteSpace(imageTag))
+ {
+ configureContainer = dbxBuilder => dbxBuilder.WithImageTag(imageTag);
+ }
+
+ return WithDbx(builder, configureContainer, containerName);
+ }
private static void ConfigureDbGateContainer(EnvironmentCallbackContext context, IResourceBuilder builder)
{
@@ -78,6 +138,30 @@ private static void ConfigureDbGateContainer(EnvironmentCallbackContext context,
context.EnvironmentVariables["CONNECTIONS"] = connectionId;
}
}
+
+ private static async Task ConfigureDbxContainer(
+ EnvironmentCallbackContext context,
+ IResourceBuilder dbxBuilder,
+ IResourceBuilder builder
+ )
+ {
+ var redisResource = builder.Resource;
+
+ dbxBuilder.Resource.AddConnection(
+ new DbxConnectionConfig
+ {
+ Id = redisResource.Name,
+ Name = redisResource.Name,
+ DbType = DbxDatabaseType.Redis,
+ Host = redisResource.Name,
+ Port = ushort.Parse(redisResource.GetEndpoint("secondary").TargetPort!.Value.ToString()),
+ Username = string.Empty,
+ Password = redisResource.PasswordParameter is not null
+ ? await redisResource.PasswordParameter.GetValueAsync(context.CancellationToken) ?? string.Empty
+ : string.Empty,
+ }
+ );
+ }
}
#pragma warning restore ASPIREATS001 // AspireExport is experimental
diff --git a/src/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.csproj b/src/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.csproj
index 9b814a1f4..e3388505e 100644
--- a/src/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.csproj
+++ b/src/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions.csproj
@@ -13,6 +13,7 @@
+
diff --git a/src/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions/SqlServerBuilderExtensions.cs b/src/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions/SqlServerBuilderExtensions.cs
index 67d623fd6..4bed5efac 100644
--- a/src/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions/SqlServerBuilderExtensions.cs
+++ b/src/CommunityToolkit.Aspire.Hosting.SqlServer.Extensions/SqlServerBuilderExtensions.cs
@@ -135,6 +135,67 @@ internal static IResourceBuilder WithAdminer(this IReso
return WithAdminer(builder, configureContainer, containerName);
}
+ ///
+ /// Adds an administration and development platform for SqlServer to the application model using dbx.
+ ///
+ ///
+ /// This version of the package defaults to the tag of the container image.
+ /// This overload is not available in polyglot app hosts. Use instead.
+ ///
+ /// The SqlServer server resource builder.
+ /// Configuration callback for dbx container resource.
+ /// The name of the container (Optional).
+ ///
+ /// Use in application host with a SqlServer resource
+ ///
+ /// var builder = DistributedApplication.CreateBuilder(args);
+ ///
+ /// var sqlserver = builder.AddSqlServer("sqlserver")
+ /// .WithDbx();
+ /// var db = sqlserver.AddDatabase("db");
+ ///
+ /// var api = builder.AddProject<Projects.Api>("api")
+ /// .WithReference(db);
+ ///
+ /// builder.Build().Run();
+ ///
+ ///
+ /// A reference to the .
+ [AspireExportIgnore(Reason = "Action> is not supported reliably in polyglot app hosts. Use the container options overload instead.")]
+ public static IResourceBuilder WithDbx(this IResourceBuilder builder, Action>? configureContainer = null, string? containerName = null)
+ {
+ ArgumentNullException.ThrowIfNull(builder);
+
+ containerName ??= "dbx";
+ var dbxBuilder = DbxBuilderExtensions.AddDbx(builder.ApplicationBuilder, containerName);
+
+ dbxBuilder
+ .WithEnvironment(context => ConfigureDbxContainer(context, dbxBuilder, builder));
+
+ configureContainer?.Invoke(dbxBuilder);
+
+ return builder;
+ }
+
+ ///
+ /// Adds an administration and development platform for SqlServer to the application model using dbx.
+ ///
+ /// The SqlServer server resource builder.
+ /// The name of the container (Optional).
+ /// Optional image tag override for the dbx container.
+ /// A reference to the .
+ [AspireExport]
+ internal static IResourceBuilder WithDbx(this IResourceBuilder builder, string? containerName = null, string? imageTag = null)
+ {
+ Action>? configureContainer = null;
+ if (!string.IsNullOrWhiteSpace(imageTag))
+ {
+ configureContainer = dbxBuilder => dbxBuilder.WithImageTag(imageTag);
+ }
+
+ return WithDbx(builder, configureContainer, containerName);
+ }
+
private static void ConfigureDbGateContainer(EnvironmentCallbackContext context, IResourceBuilder builder)
{
var sqlServerResource = builder.Resource;
@@ -203,6 +264,28 @@ private static async Task ConfigureAdminerContainer(EnvironmentCallbackContext c
string servers_json = JsonSerializer.Serialize(servers);
context.EnvironmentVariables["ADMINER_SERVERS"] = servers_json;
}
+
+ private static async Task ConfigureDbxContainer(
+ EnvironmentCallbackContext context,
+ IResourceBuilder dbxBuilder,
+ IResourceBuilder builder
+ )
+ {
+ var sqlServerServerResource = builder.Resource;
+
+ dbxBuilder.Resource.AddConnection(
+ new DbxConnectionConfig
+ {
+ Id = sqlServerServerResource.Name,
+ Name = sqlServerServerResource.Name,
+ DbType = DbxDatabaseType.SqlServer,
+ Host = sqlServerServerResource.Name,
+ Port = ushort.Parse(sqlServerServerResource.PrimaryEndpoint.TargetPort!.Value.ToString()),
+ Username = await sqlServerServerResource.UserNameReference.GetValueAsync(context.CancellationToken) ?? string.Empty,
+ Password = await sqlServerServerResource.PasswordParameter.GetValueAsync(context.CancellationToken) ?? string.Empty,
+ }
+ );
+ }
}
#pragma warning restore ASPIREATS001 // AspireExport is experimental
diff --git a/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/AddDbxTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/AddDbxTests.cs
new file mode 100644
index 000000000..d973973ed
--- /dev/null
+++ b/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/AddDbxTests.cs
@@ -0,0 +1,203 @@
+using System.Net.Sockets;
+using Aspire.Hosting;
+using Aspire.Hosting.Utils;
+using CommunityToolkit.Aspire.Testing;
+
+namespace CommunityToolkit.Aspire.Hosting.Dbx.Tests;
+
+public class AddDbxTests
+{
+ [Fact]
+ public void AddDbxContainerWithDefaultsAddsAnnotationMetadata()
+ {
+ var appBuilder = DistributedApplication.CreateBuilder();
+
+ var dbx = appBuilder.AddDbx();
+
+ using var app = appBuilder.Build();
+
+ var appModel = app.Services.GetRequiredService();
+
+ var containerResource = Assert.Single(appModel.Resources.OfType());
+ Assert.Equal("dbx", containerResource.Name);
+
+ var endpoints = containerResource.Annotations.OfType();
+ Assert.Single(endpoints);
+
+ var primaryEndpoint = Assert.Single(endpoints, e => e.Name == "http");
+ Assert.Equal(4224, primaryEndpoint.TargetPort);
+ Assert.False(primaryEndpoint.IsExternal);
+ Assert.Equal("http", primaryEndpoint.Name);
+ Assert.Null(primaryEndpoint.Port);
+ Assert.Equal(ProtocolType.Tcp, primaryEndpoint.Protocol);
+ Assert.Equal("http", primaryEndpoint.Transport);
+ Assert.Equal("http", primaryEndpoint.UriScheme);
+
+ var containerAnnotation = Assert.Single(containerResource.Annotations.OfType());
+ Assert.Equal(DbxContainerImageTags.Tag, containerAnnotation.Tag);
+ Assert.Equal(DbxContainerImageTags.Image, containerAnnotation.Image);
+ Assert.Equal(DbxContainerImageTags.Registry, containerAnnotation.Registry);
+
+ var annotations = dbx.Resource.Annotations;
+
+ Assert.Contains(ManifestPublishingCallbackAnnotation.Ignore, annotations);
+ }
+
+ [Fact]
+ public void AddDbxContainerWithPort()
+ {
+ var appBuilder = DistributedApplication.CreateBuilder();
+
+ var dbx = appBuilder.AddDbx(port: 9090);
+
+ using var app = appBuilder.Build();
+
+ var appModel = app.Services.GetRequiredService();
+
+ var containerResource = Assert.Single(appModel.Resources.OfType());
+ Assert.Equal("dbx", containerResource.Name);
+
+ var endpoints = containerResource.Annotations.OfType();
+ Assert.Single(endpoints);
+
+ var primaryEndpoint = Assert.Single(endpoints, e => e.Name == "http");
+ Assert.Equal(4224, primaryEndpoint.TargetPort);
+ Assert.False(primaryEndpoint.IsExternal);
+ Assert.Equal("http", primaryEndpoint.Name);
+ Assert.Equal(9090, primaryEndpoint.Port);
+ Assert.Equal(ProtocolType.Tcp, primaryEndpoint.Protocol);
+ Assert.Equal("http", primaryEndpoint.Transport);
+ Assert.Equal("http", primaryEndpoint.UriScheme);
+
+ var containerAnnotation = Assert.Single(containerResource.Annotations.OfType());
+ Assert.Equal(DbxContainerImageTags.Tag, containerAnnotation.Tag);
+ Assert.Equal(DbxContainerImageTags.Image, containerAnnotation.Image);
+ Assert.Equal(DbxContainerImageTags.Registry, containerAnnotation.Registry);
+
+ var annotations = dbx.Resource.Annotations;
+
+ Assert.Contains(ManifestPublishingCallbackAnnotation.Ignore, annotations);
+ }
+
+ [Fact]
+ public void MultipleAddDbxCallsShouldAddOneDbxResource()
+ {
+ var appBuilder = DistributedApplication.CreateBuilder();
+
+ appBuilder.AddDbx();
+ appBuilder.AddDbx();
+
+ using var app = appBuilder.Build();
+
+ var appModel = app.Services.GetRequiredService();
+
+ var containerResource = Assert.Single(appModel.Resources.OfType());
+ Assert.Equal("dbx", containerResource.Name);
+ }
+
+ [Fact]
+ public void VerifyWithHostPort()
+ {
+ var appBuilder = DistributedApplication.CreateBuilder();
+
+ var dbx = appBuilder.AddDbx().WithHostPort(9090);
+
+ using var app = appBuilder.Build();
+
+ var appModel = app.Services.GetRequiredService();
+
+ var containerResource = Assert.Single(appModel.Resources.OfType());
+ Assert.Equal("dbx", containerResource.Name);
+
+ var endpoints = containerResource.Annotations.OfType();
+ Assert.Single(endpoints);
+
+ var primaryEndpoint = Assert.Single(endpoints, e => e.Name == "http");
+ Assert.Equal(4224, primaryEndpoint.TargetPort);
+ Assert.False(primaryEndpoint.IsExternal);
+ Assert.Equal("http", primaryEndpoint.Name);
+ Assert.Equal(9090, primaryEndpoint.Port);
+ Assert.Equal(ProtocolType.Tcp, primaryEndpoint.Protocol);
+ Assert.Equal("http", primaryEndpoint.Transport);
+ Assert.Equal("http", primaryEndpoint.UriScheme);
+
+ var containerAnnotation = Assert.Single(containerResource.Annotations.OfType());
+ Assert.Equal(DbxContainerImageTags.Tag, containerAnnotation.Tag);
+ Assert.Equal(DbxContainerImageTags.Image, containerAnnotation.Image);
+ Assert.Equal(DbxContainerImageTags.Registry, containerAnnotation.Registry);
+
+ var annotations = dbx.Resource.Annotations;
+
+ Assert.Contains(ManifestPublishingCallbackAnnotation.Ignore, annotations);
+ }
+
+ [Fact]
+ public void WithDbxShouldAddOneDbxResourceForMultipleDatabaseTypes()
+ {
+ var builder = DistributedApplication.CreateBuilder();
+
+ builder.AddMongoDB("mongodb1")
+ .WithDbx();
+
+ builder.AddMongoDB("mongodb2")
+ .WithDbx();
+
+ builder.AddPostgres("postgres1")
+ .WithDbx();
+
+ builder.AddPostgres("postgres2")
+ .WithDbx();
+
+ builder.AddRedis("redis1")
+ .WithDbx();
+
+ builder.AddRedis("redis2")
+ .WithDbx();
+
+ builder.AddSqlServer("sqlserver1")
+ .WithDbx();
+
+ builder.AddSqlServer("sqlserver2")
+ .WithDbx();
+
+ builder.AddMySql("mysql1")
+ .WithDbx();
+
+ builder.AddMySql("mysql2")
+ .WithDbx();
+
+ using var app = builder.Build();
+
+ var appModel = app.Services.GetRequiredService();
+
+ var dbxResource = appModel.Resources.OfType().SingleOrDefault();
+
+ var containerResource = Assert.Single(appModel.Resources.OfType());
+ Assert.Equal("dbx", containerResource.Name);
+ }
+
+ [Fact]
+ [RequiresDocker]
+ public async Task AddDbxWithDefaultsAddsUrlAnnotations()
+ {
+ using var builder = TestDistributedApplicationBuilder.Create();
+
+ var dbx = builder.AddDbx("dbx");
+
+ var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+ dbx.OnResourceEndpointsAllocated((resource, @event, ct) =>
+ {
+ tcs.SetResult();
+ return Task.CompletedTask;
+ });
+
+ var app = await builder.BuildAsync();
+ await app.StartAsync();
+ await tcs.Task;
+
+ var urls = dbx.Resource.Annotations.OfType();
+ Assert.Single(urls, u => u.DisplayText == "dbx Dashboard");
+
+ await app.StopAsync();
+ }
+}
diff --git a/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/AppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/AppHostTests.cs
new file mode 100644
index 000000000..8ae659e84
--- /dev/null
+++ b/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/AppHostTests.cs
@@ -0,0 +1,19 @@
+using CommunityToolkit.Aspire.Testing;
+
+namespace CommunityToolkit.Aspire.Hosting.Dbx.Tests;
+
+[RequiresDocker]
+public class AppHostTests(AspireIntegrationTestFixture fixture) : IClassFixture>
+{
+ [Fact]
+ public async Task ResourceStartsAndRespondsOk()
+ {
+ var resourceName = "dbx";
+ await fixture.ResourceNotificationService.WaitForResourceHealthyAsync(resourceName).WaitAsync(TimeSpan.FromMinutes(5));
+ var httpClient = fixture.CreateHttpClient(resourceName);
+
+ var response = await httpClient.GetAsync("/");
+
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ }
+}
\ No newline at end of file
diff --git a/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests.csproj b/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests.csproj
new file mode 100644
index 000000000..b66fe08bc
--- /dev/null
+++ b/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests.csproj
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/DbxPublicApiTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/DbxPublicApiTests.cs
new file mode 100644
index 000000000..51352091f
--- /dev/null
+++ b/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/DbxPublicApiTests.cs
@@ -0,0 +1,42 @@
+using Aspire.Hosting;
+
+namespace CommunityToolkit.Aspire.Hosting.Dbx.Tests;
+
+public class DbxPublicApiTests
+{
+ [Fact]
+ public void AddDbxContainerShouldThrowWhenBuilderIsNull()
+ {
+ IDistributedApplicationBuilder builder = null!;
+
+ var action = () => builder.AddDbx();
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(builder), exception.ParamName);
+ }
+
+ [Fact]
+ public void AddDbxContainerShouldThrowWhenNameIsNull()
+ {
+ IDistributedApplicationBuilder builder = new DistributedApplicationBuilder([]);
+ string name = null!;
+
+ var action = () => builder.AddDbx(name);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(name), exception.ParamName);
+ }
+
+ [Fact]
+ public void WithHostPortShouldThrowWhenBuilderIsNull()
+ {
+ IResourceBuilder builder = null!;
+
+ Func>? action = null;
+
+ action = () => builder.WithHostPort(9090);
+
+ var exception = Assert.Throws(action);
+ Assert.Equal(nameof(builder), exception.ParamName);
+ }
+}
diff --git a/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/TypeScriptAppHostTests.cs b/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/TypeScriptAppHostTests.cs
new file mode 100644
index 000000000..8cdc8ef9a
--- /dev/null
+++ b/tests/CommunityToolkit.Aspire.Hosting.Dbx.Tests/TypeScriptAppHostTests.cs
@@ -0,0 +1,18 @@
+using CommunityToolkit.Aspire.Testing;
+
+namespace CommunityToolkit.Aspire.Hosting.Dbx.Tests;
+
+[RequiresDocker]
+public class TypeScriptAppHostTests
+{
+ [Fact]
+ public async Task TypeScriptAppHostCompilesAndStarts()
+ {
+ await TypeScriptAppHostTest.Run(
+ appHostProject: "CommunityToolkit.Aspire.Hosting.Dbx.AppHost.TypeScript",
+ packageName: "CommunityToolkit.Aspire.Hosting.Dbx",
+ exampleName: "dbx",
+ waitForResources: ["dbx"],
+ cancellationToken: TestContext.Current.CancellationToken);
+ }
+}