From 7b168708997299d5fc0a1e57d2415761db806acb Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 09:13:33 -0400 Subject: [PATCH 01/22] wip --- README.md | 7 +- api-keys.example.json | 7 + bun.lockb | Bin 324954 -> 325330 bytes example.env | 10 +- package-lock.json | 9296 +++++++++++++++++ package.json | 37 +- scripts/discord/sync-commands.ts | 87 + src/auth/admin.ts | 23 +- src/auth/api-keys.ts | 2 +- src/auth/discord-context.ts | 36 + src/auth/express-auth-context.ts | 12 + src/auth/express-discord-context.ts | 12 + src/auth/jwt.ts | 4 +- src/auth/protected-resource.ts | 24 +- src/auth/user-context.ts | 29 + src/core/RaidHubRoute.ts | 54 + src/core/RaidHubRouterTypes.ts | 4 + src/index.ts | 16 +- src/integrations/discord/command-registry.ts | 244 + src/integrations/discord/context-jwt.ts | 24 + src/integrations/discord/interactions.ts | 208 + src/integrations/discord/message-builders.ts | 28 + src/integrations/discord/response-registry.ts | 205 + src/integrations/discord/types.ts | 45 + src/integrations/postgres/reader.ts | 2 +- src/integrations/postgres/transactional.ts | 2 +- src/routes/authorize/admin.test.ts | 2 +- src/routes/authorize/user.test.ts | 2 +- src/routes/index.ts | 5 + src/routes/instance.ts | 50 +- src/routes/player/membershipId/history.ts | 2 +- src/routes/player/membershipId/instances.ts | 5 +- src/routes/player/membershipId/profile.ts | 2 +- src/routes/player/membershipId/teammates.ts | 2 +- src/routes/player/search.ts | 9 +- src/routes/subscriptions/discord/index.ts | 23 + src/routes/subscriptions/discord/webhooks.ts | 98 + src/routes/subscriptions/index.ts | 11 + .../components/DiscordSubscriptionWebhook.ts | 94 + src/schema/errors/ErrorCode.ts | 1 + src/services/manifest/urls.ts | 2 +- src/services/search/player-search.test.ts | 2 + src/services/search/player-search.ts | 13 +- .../subscriptions/discord-webhooks.test.ts | 195 + .../subscriptions/discord-webhooks.ts | 617 ++ tsconfig.json | 1 + 46 files changed, 11452 insertions(+), 102 deletions(-) create mode 100644 api-keys.example.json create mode 100644 package-lock.json create mode 100644 scripts/discord/sync-commands.ts create mode 100644 src/auth/discord-context.ts create mode 100644 src/auth/express-auth-context.ts create mode 100644 src/auth/express-discord-context.ts create mode 100644 src/auth/user-context.ts create mode 100644 src/integrations/discord/command-registry.ts create mode 100644 src/integrations/discord/context-jwt.ts create mode 100644 src/integrations/discord/interactions.ts create mode 100644 src/integrations/discord/message-builders.ts create mode 100644 src/integrations/discord/response-registry.ts create mode 100644 src/integrations/discord/types.ts create mode 100644 src/routes/subscriptions/discord/index.ts create mode 100644 src/routes/subscriptions/discord/webhooks.ts create mode 100644 src/routes/subscriptions/index.ts create mode 100644 src/schema/components/DiscordSubscriptionWebhook.ts create mode 100644 src/services/subscriptions/discord-webhooks.test.ts create mode 100644 src/services/subscriptions/discord-webhooks.ts diff --git a/README.md b/README.md index 5744ca9f..b7d07c48 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,11 @@ Note: you will need to clone the [RaidHub-Services](https://github.com/Raid-Hub/ ### Turning the API On 1. Run `cp example.env .env` and make any changes -2. Run `bun dev` -3. By default the API is available at `http://localhost:8000` +2. Copy `api-keys.example.json` to `api-keys.json` and set at least one `key` (use `origin` `"*"` for local tools such as **raidhub-discord**). Point `API_KEYS_PATH` in `.env` at that file (defaults to `./api-keys.json`). +3. Run `bun dev` +4. By default the API is available at `http://localhost:8000` + +With `PROD=true`, every request must include a valid `x-api-key` header matching an entry in `api-keys.json`. ### Open API diff --git a/api-keys.example.json b/api-keys.example.json new file mode 100644 index 00000000..d86ce508 --- /dev/null +++ b/api-keys.example.json @@ -0,0 +1,7 @@ +[ + { + "description": "Copy to api-keys.json and set unique keys. origin * allows any Origin header.", + "origin": "*", + "key": "00000000-0000-4000-8000-000000000001" + } +] diff --git a/bun.lockb b/bun.lockb index c1b89aeb3ad80ae5f8f47efc55c751506f091652..a07a944f3ce2e28a021dec65f33288860f39e54c 100755 GIT binary patch delta 58447 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 delta 58540 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�rOu6 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 diff --git a/example.env b/example.env index 848bd67a..894696f6 100644 --- a/example.env +++ b/example.env @@ -11,6 +11,9 @@ CLIENT_SECRET=123abc ADMIN_CLIENT_SECRET=abc123 JWT_SECRET=secretkey +# When PROD=true, clients must send x-api-key matching an entry here (copy to api-keys.json). +API_KEYS_PATH=./api-keys.json + RABBIT_API_USER=guest RABBIT_API_PASSWORD=guest @@ -24,4 +27,9 @@ SENTRY_DSN="" SENTRY_ENVIRONMENT="development" # Logging -LOG_LEVEL="info" \ No newline at end of file +LOG_LEVEL="info" + +# Integration +DISCORD_PUBLIC_KEY="" +DISCORD_BOT_TOKEN="" +DISCORD_APPLICATION_ID="" \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..ffd0163d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,9296 @@ +{ + "name": "raidhub-api", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "raidhub-api", + "version": "1.0.0", + "license": "UNLICENSED", + "dependencies": { + "@aws-sdk/client-s3": "^3.908.0", + "@clickhouse/client": "^1.5.0", + "@sentry/bun": "^10.23.0", + "@types/pg": "^8.15.6", + "amqplib": "^0.10.3", + "bungie-net-core": "2.1.3", + "compression": "^1.7.4", + "discord-api-types": "^0.38.47", + "express": "^4.18.2", + "jsonwebtoken": "^9.0.2", + "pg": "^8.16.3", + "prom-client": "^15.1.1", + "zod": "^3.22.4" + }, + "devDependencies": { + "@asteasolutions/zod-to-openapi": "^6.3.1", + "@types/amqplib": "^0.10.5", + "@types/compression": "^1.7.5", + "@types/cors": "^2.8.15", + "@types/express": "^4.17.20", + "@types/jsonwebtoken": "^9.0.5", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^6.19.1", + "@typescript-eslint/parser": "^6.19.1", + "bun-types": "^1.0.35", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", + "husky": "^9.0.6", + "lint-staged": "^15.2.0", + "prettier": "^3.0.3", + "prettier-plugin-organize-imports": "^3.2.4", + "redoc-cli": "^0.13.21", + "supertest": "^6.3.4", + "typescript": "5.4" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@acuminous/bitsyntax": { + "version": "0.1.2", + "license": "MIT", + "dependencies": { + "buffer-more-ints": "~1.0.0", + "debug": "^4.3.4", + "safe-buffer": "~5.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@apm-js-collab/code-transformer": { + "version": "0.8.2", + "license": "Apache-2.0" + }, + "node_modules/@apm-js-collab/tracing-hooks": { + "version": "0.3.1", + "license": "Apache-2.0", + "dependencies": { + "@apm-js-collab/code-transformer": "^0.8.0", + "debug": "^4.4.1", + "module-details-from-path": "^1.0.4" + } + }, + "node_modules/@apm-js-collab/tracing-hooks/node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@asteasolutions/zod-to-openapi": { + "version": "6.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "openapi3-ts": "^4.1.2" + }, + "peerDependencies": { + "zod": "^3.20.2" + } + }, + "node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/crc32c": { + "version": "5.2.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha1-browser": { + "version": "5.2.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-utf8/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-utf8/node_modules/@smithy/util-buffer-from/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8/node_modules/@smithy/util-buffer-from/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8/node_modules/@smithy/util-buffer-from/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-s3": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha1-browser": "5.2.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.908.0", + "@aws-sdk/credential-provider-node": "3.908.0", + "@aws-sdk/middleware-bucket-endpoint": "3.901.0", + "@aws-sdk/middleware-expect-continue": "3.901.0", + "@aws-sdk/middleware-flexible-checksums": "3.908.0", + "@aws-sdk/middleware-host-header": "3.901.0", + "@aws-sdk/middleware-location-constraint": "3.901.0", + "@aws-sdk/middleware-logger": "3.901.0", + "@aws-sdk/middleware-recursion-detection": "3.901.0", + "@aws-sdk/middleware-sdk-s3": "3.908.0", + "@aws-sdk/middleware-ssec": "3.901.0", + "@aws-sdk/middleware-user-agent": "3.908.0", + "@aws-sdk/region-config-resolver": "3.901.0", + "@aws-sdk/signature-v4-multi-region": "3.908.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@aws-sdk/util-user-agent-browser": "3.907.0", + "@aws-sdk/util-user-agent-node": "3.908.0", + "@aws-sdk/xml-builder": "3.901.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.15.0", + "@smithy/eventstream-serde-browser": "^4.2.0", + "@smithy/eventstream-serde-config-resolver": "^4.3.0", + "@smithy/eventstream-serde-node": "^4.2.0", + "@smithy/fetch-http-handler": "^5.3.1", + "@smithy/hash-blob-browser": "^4.2.1", + "@smithy/hash-node": "^4.2.0", + "@smithy/hash-stream-node": "^4.2.0", + "@smithy/invalid-dependency": "^4.2.0", + "@smithy/md5-js": "^4.2.0", + "@smithy/middleware-content-length": "^4.2.0", + "@smithy/middleware-endpoint": "^4.3.1", + "@smithy/middleware-retry": "^4.4.1", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.1", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.0", + "@smithy/util-defaults-mode-node": "^4.2.1", + "@smithy/util-endpoints": "^3.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/util-stream": "^4.5.0", + "@smithy/util-utf8": "^4.2.0", + "@smithy/util-waiter": "^4.2.0", + "@smithy/uuid": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.908.0", + "@aws-sdk/middleware-host-header": "3.901.0", + "@aws-sdk/middleware-logger": "3.901.0", + "@aws-sdk/middleware-recursion-detection": "3.901.0", + "@aws-sdk/middleware-user-agent": "3.908.0", + "@aws-sdk/region-config-resolver": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@aws-sdk/util-user-agent-browser": "3.907.0", + "@aws-sdk/util-user-agent-node": "3.908.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.15.0", + "@smithy/fetch-http-handler": "^5.3.1", + "@smithy/hash-node": "^4.2.0", + "@smithy/invalid-dependency": "^4.2.0", + "@smithy/middleware-content-length": "^4.2.0", + "@smithy/middleware-endpoint": "^4.3.1", + "@smithy/middleware-retry": "^4.4.1", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.1", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.0", + "@smithy/util-defaults-mode-node": "^4.2.1", + "@smithy/util-endpoints": "^3.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@aws-sdk/xml-builder": "3.901.0", + "@smithy/core": "^3.15.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/signature-v4": "^5.3.0", + "@smithy/smithy-client": "^4.7.1", + "@smithy/types": "^4.6.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.908.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.908.0", + "@aws-sdk/types": "3.901.0", + "@smithy/fetch-http-handler": "^5.3.1", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.1", + "@smithy/types": "^4.6.0", + "@smithy/util-stream": "^4.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.908.0", + "@aws-sdk/credential-provider-env": "3.908.0", + "@aws-sdk/credential-provider-http": "3.908.0", + "@aws-sdk/credential-provider-process": "3.908.0", + "@aws-sdk/credential-provider-sso": "3.908.0", + "@aws-sdk/credential-provider-web-identity": "3.908.0", + "@aws-sdk/nested-clients": "3.908.0", + "@aws-sdk/types": "3.901.0", + "@smithy/credential-provider-imds": "^4.2.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.908.0", + "@aws-sdk/credential-provider-http": "3.908.0", + "@aws-sdk/credential-provider-ini": "3.908.0", + "@aws-sdk/credential-provider-process": "3.908.0", + "@aws-sdk/credential-provider-sso": "3.908.0", + "@aws-sdk/credential-provider-web-identity": "3.908.0", + "@aws-sdk/types": "3.901.0", + "@smithy/credential-provider-imds": "^4.2.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.908.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.908.0", + "@aws-sdk/core": "3.908.0", + "@aws-sdk/token-providers": "3.908.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.908.0", + "@aws-sdk/nested-clients": "3.908.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-arn-parser": "3.893.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-config-provider": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@aws-crypto/crc32c": "5.2.0", + "@aws-crypto/util": "5.2.0", + "@aws-sdk/core": "3.908.0", + "@aws-sdk/types": "3.901.0", + "@smithy/is-array-buffer": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-stream": "^4.5.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-location-constraint": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@aws/lambda-invoke-store": "^0.0.1", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.908.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-arn-parser": "3.893.0", + "@smithy/core": "^3.15.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/signature-v4": "^5.3.0", + "@smithy/smithy-client": "^4.7.1", + "@smithy/types": "^4.6.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-stream": "^4.5.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-ssec": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.908.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@smithy/core": "^3.15.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.908.0", + "@aws-sdk/middleware-host-header": "3.901.0", + "@aws-sdk/middleware-logger": "3.901.0", + "@aws-sdk/middleware-recursion-detection": "3.901.0", + "@aws-sdk/middleware-user-agent": "3.908.0", + "@aws-sdk/region-config-resolver": "3.901.0", + "@aws-sdk/types": "3.901.0", + "@aws-sdk/util-endpoints": "3.901.0", + "@aws-sdk/util-user-agent-browser": "3.907.0", + "@aws-sdk/util-user-agent-node": "3.908.0", + "@smithy/config-resolver": "^4.3.0", + "@smithy/core": "^3.15.0", + "@smithy/fetch-http-handler": "^5.3.1", + "@smithy/hash-node": "^4.2.0", + "@smithy/invalid-dependency": "^4.2.0", + "@smithy/middleware-content-length": "^4.2.0", + "@smithy/middleware-endpoint": "^4.3.1", + "@smithy/middleware-retry": "^4.4.1", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/smithy-client": "^4.7.1", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.0", + "@smithy/util-defaults-mode-node": "^4.2.1", + "@smithy/util-endpoints": "^3.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-sdk-s3": "3.908.0", + "@aws-sdk/types": "3.901.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/signature-v4": "^5.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.908.0", + "@aws-sdk/nested-clients": "3.908.0", + "@aws-sdk/types": "3.901.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-arn-parser": { + "version": "3.893.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-endpoints": "^3.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.893.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.907.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.901.0", + "@smithy/types": "^4.6.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.908.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.908.0", + "@aws-sdk/types": "3.901.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.901.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "fast-xml-parser": "5.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.0.1", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.1", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.3", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.1", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.1", + "@babel/parser": "^7.24.1", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache/node_modules/yallist": { + "version": "3.1.1", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles": { + "version": "3.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert": { + "version": "1.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules/color-name": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/chalk/node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.1", + "dev": true, + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@clickhouse/client": { + "version": "1.5.0", + "license": "Apache-2.0", + "dependencies": { + "@clickhouse/client-common": "1.5.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@clickhouse/client-common": { + "version": "1.5.0", + "license": "Apache-2.0" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@emotion/stylis": { + "version": "0.8.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.7.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@exodus/schemasafe": { + "version": "1.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.204.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "2.2.0", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.204.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.204.0", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-amqplib": { + "version": "0.51.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-connect": { + "version": "0.48.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/connect": "3.4.38" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-dataloader": { + "version": "0.22.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.204.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-express": { + "version": "0.53.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fs": { + "version": "0.24.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.204.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-generic-pool": { + "version": "0.48.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.204.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-graphql": { + "version": "0.52.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.204.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-hapi": { + "version": "0.51.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http": { + "version": "0.204.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.1.0", + "@opentelemetry/instrumentation": "0.204.0", + "@opentelemetry/semantic-conventions": "^1.29.0", + "forwarded-parse": "2.1.2" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/core": { + "version": "2.1.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/instrumentation-ioredis": { + "version": "0.52.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/redis-common": "^0.38.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-kafkajs": { + "version": "0.14.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/semantic-conventions": "^1.30.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-knex": { + "version": "0.49.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/semantic-conventions": "^1.33.1" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-koa": { + "version": "0.52.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-lru-memoizer": { + "version": "0.49.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.204.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongodb": { + "version": "0.57.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongoose": { + "version": "0.51.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql": { + "version": "0.50.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/mysql": "2.15.27" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql2": { + "version": "0.51.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@opentelemetry/sql-common": "^0.41.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg": { + "version": "0.57.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/semantic-conventions": "^1.34.0", + "@opentelemetry/sql-common": "^0.41.0", + "@types/pg": "8.15.5", + "@types/pg-pool": "2.0.6" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg/node_modules/@types/pg": { + "version": "8.15.5", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@opentelemetry/instrumentation-redis": { + "version": "0.53.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/redis-common": "^0.38.0", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-tedious": { + "version": "0.23.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/tedious": "^4.0.14" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-undici": { + "version": "0.15.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0", + "@opentelemetry/instrumentation": "^0.204.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.7.0" + } + }, + "node_modules/@opentelemetry/redis-common": { + "version": "0.38.2", + "license": "Apache-2.0", + "engines": { + "node": "^18.19.0 || >=20.6.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "2.2.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.2.0", + "@opentelemetry/resources": "2.2.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.37.0", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sql-common": { + "version": "0.41.2", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^2.0.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0" + } + }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/@prisma/instrumentation": { + "version": "6.15.0", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0 || ^0.57.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.8" + } + }, + "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/instrumentation": { + "version": "0.57.2", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.57.2", + "@types/shimmer": "^1.2.0", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/instrumentation/node_modules/@opentelemetry/api-logs": { + "version": "0.57.2", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@redocly/ajv": { + "version": "8.11.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@redocly/ajv/node_modules/json-schema-traverse": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@redocly/config": { + "version": "0.1.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@redocly/openapi-core": { + "version": "1.10.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@redocly/ajv": "^8.11.0", + "@redocly/config": "^0.1.4", + "colorette": "^1.2.0", + "js-levenshtein": "^1.1.6", + "js-yaml": "^4.1.0", + "lodash.isequal": "^4.5.0", + "minimatch": "^5.0.1", + "node-fetch": "^2.6.1", + "pluralize": "^8.0.0", + "yaml-ast-parser": "0.0.43" + }, + "engines": { + "node": ">=14.19.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@redocly/openapi-core/node_modules/colorette": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@redocly/openapi-core/node_modules/minimatch": { + "version": "5.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@redocly/openapi-core/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@sentry/bun": { + "version": "10.23.0", + "license": "MIT", + "dependencies": { + "@sentry/core": "10.23.0", + "@sentry/node": "10.23.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/core": { + "version": "10.23.0", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/node": { + "version": "10.23.0", + "license": "MIT", + "dependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^2.1.0", + "@opentelemetry/core": "^2.1.0", + "@opentelemetry/instrumentation": "^0.204.0", + "@opentelemetry/instrumentation-amqplib": "0.51.0", + "@opentelemetry/instrumentation-connect": "0.48.0", + "@opentelemetry/instrumentation-dataloader": "0.22.0", + "@opentelemetry/instrumentation-express": "0.53.0", + "@opentelemetry/instrumentation-fs": "0.24.0", + "@opentelemetry/instrumentation-generic-pool": "0.48.0", + "@opentelemetry/instrumentation-graphql": "0.52.0", + "@opentelemetry/instrumentation-hapi": "0.51.0", + "@opentelemetry/instrumentation-http": "0.204.0", + "@opentelemetry/instrumentation-ioredis": "0.52.0", + "@opentelemetry/instrumentation-kafkajs": "0.14.0", + "@opentelemetry/instrumentation-knex": "0.49.0", + "@opentelemetry/instrumentation-koa": "0.52.0", + "@opentelemetry/instrumentation-lru-memoizer": "0.49.0", + "@opentelemetry/instrumentation-mongodb": "0.57.0", + "@opentelemetry/instrumentation-mongoose": "0.51.0", + "@opentelemetry/instrumentation-mysql": "0.50.0", + "@opentelemetry/instrumentation-mysql2": "0.51.0", + "@opentelemetry/instrumentation-pg": "0.57.0", + "@opentelemetry/instrumentation-redis": "0.53.0", + "@opentelemetry/instrumentation-tedious": "0.23.0", + "@opentelemetry/instrumentation-undici": "0.15.0", + "@opentelemetry/resources": "^2.1.0", + "@opentelemetry/sdk-trace-base": "^2.1.0", + "@opentelemetry/semantic-conventions": "^1.37.0", + "@prisma/instrumentation": "6.15.0", + "@sentry/core": "10.23.0", + "@sentry/node-core": "10.23.0", + "@sentry/opentelemetry": "10.23.0", + "import-in-the-middle": "^1.14.2", + "minimatch": "^9.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/node-core": { + "version": "10.23.0", + "license": "MIT", + "dependencies": { + "@apm-js-collab/tracing-hooks": "^0.3.1", + "@sentry/core": "10.23.0", + "@sentry/opentelemetry": "10.23.0", + "import-in-the-middle": "^1.14.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0", + "@opentelemetry/core": "^1.30.1 || ^2.1.0", + "@opentelemetry/instrumentation": ">=0.57.1 <1", + "@opentelemetry/resources": "^1.30.1 || ^2.1.0", + "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", + "@opentelemetry/semantic-conventions": "^1.37.0" + } + }, + "node_modules/@sentry/node/node_modules/minimatch": { + "version": "9.0.3", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@sentry/node/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@sentry/opentelemetry": { + "version": "10.23.0", + "license": "MIT", + "dependencies": { + "@sentry/core": "10.23.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0", + "@opentelemetry/core": "^1.30.1 || ^2.1.0", + "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", + "@opentelemetry/semantic-conventions": "^1.37.0" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader": { + "version": "5.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader-native": { + "version": "4.2.1", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-base64": "^4.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "4.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-config-provider": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "3.15.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-stream": "^4.5.0", + "@smithy/util-utf8": "^4.2.0", + "@smithy/uuid": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-codec": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^4.6.0", + "@smithy/util-hex-encoding": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-browser": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^4.2.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "4.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-node": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^4.2.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-universal": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-codec": "^4.2.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.3.1", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.0", + "@smithy/querystring-builder": "^4.2.0", + "@smithy/types": "^4.6.0", + "@smithy/util-base64": "^4.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-blob-browser": { + "version": "4.2.1", + "license": "Apache-2.0", + "dependencies": { + "@smithy/chunked-blob-reader": "^5.2.0", + "@smithy/chunked-blob-reader-native": "^4.2.1", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-stream-node": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/md5-js": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "4.3.1", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.15.0", + "@smithy/middleware-serde": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", + "@smithy/url-parser": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "4.4.1", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/service-error-classification": "^4.2.0", + "@smithy/smithy-client": "^4.7.1", + "@smithy/types": "^4.6.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-retry": "^4.2.0", + "@smithy/uuid": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "4.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.2.0", + "@smithy/shared-ini-file-loader": "^4.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/querystring-builder": "^4.2.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "5.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "@smithy/util-uri-escape": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "4.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-hex-encoding": "^4.2.0", + "@smithy/util-middleware": "^4.2.0", + "@smithy/util-uri-escape": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "4.7.1", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.15.0", + "@smithy/middleware-endpoint": "^4.3.1", + "@smithy/middleware-stack": "^4.2.0", + "@smithy/protocol-http": "^5.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-stream": "^4.5.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.6.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^4.2.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "4.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "4.2.1", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "4.3.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.2.0", + "@smithy/smithy-client": "^4.7.1", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "4.2.1", + "license": "Apache-2.0", + "dependencies": { + "@smithy/config-resolver": "^4.3.0", + "@smithy/credential-provider-imds": "^4.2.0", + "@smithy/node-config-provider": "^4.3.0", + "@smithy/property-provider": "^4.2.0", + "@smithy/smithy-client": "^4.7.1", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "3.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/service-error-classification": "^4.2.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "4.5.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^5.3.1", + "@smithy/node-http-handler": "^4.3.0", + "@smithy/types": "^4.6.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-buffer-from": "^4.2.0", + "@smithy/util-hex-encoding": "^4.2.0", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-waiter": { + "version": "4.2.0", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^4.2.0", + "@smithy/types": "^4.6.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/uuid": { + "version": "1.1.0", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@types/amqplib": { + "version": "0.10.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/compression": { + "version": "1.7.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookiejar": { + "version": "2.1.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.6", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/express": { + "version": "4.17.21", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.43", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/methods": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mysql": { + "version": "2.15.27", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.11.30", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/pg": { + "version": "8.15.6", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/pg-pool": { + "version": "2.0.6", + "license": "MIT", + "dependencies": { + "@types/pg": "*" + } + }, + "node_modules/@types/pg-pool/node_modules/@types/pg": { + "version": "8.15.5", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/qs": { + "version": "6.9.14", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/shimmer": { + "version": "1.2.0", + "license": "MIT" + }, + "node_modules/@types/superagent": { + "version": "8.1.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cookiejar": "^2.1.5", + "@types/methods": "^1.1.4", + "@types/node": "*" + } + }, + "node_modules/@types/supertest": { + "version": "6.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/methods": "^1.1.4", + "@types/superagent": "^8.1.0" + } + }, + "node_modules/@types/tedious": { + "version": "4.0.14", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "dev": true, + "license": "ISC" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "dev": true, + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "dev": true, + "license": "Apache-2.0", + "peer": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "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/ajv-keywords": { + "version": "3.5.2", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/amqplib": { + "version": "0.10.3", + "license": "MIT", + "dependencies": { + "@acuminous/bitsyntax": "^0.1.2", + "buffer-more-ints": "~1.0.0", + "readable-stream": "1.x >=1.1.9", + "url-parse": "~1.5.10" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/asn1.js": { + "version": "4.10.1", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/assert": { + "version": "1.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "object.assign": "^4.1.4", + "util": "^0.10.4" + } + }, + "node_modules/assert/node_modules/util": { + "version": "0.10.4", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/assert/node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "dev": true, + "license": "ISC" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-plugin-styled-components": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "lodash": "^4.17.21", + "picomatch": "^2.3.1" + }, + "peerDependencies": { + "styled-components": ">= 2" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bintrees": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/bn.js": { + "version": "5.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.2", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/bowser": { + "version": "2.12.1", + "license": "MIT" + }, + "node_modules/boxen": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/wrap-ansi": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/boxen/node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-aes/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-des/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/browserify-rsa": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.5", + "hash-base": "~3.0", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.7", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify-sign/node_modules/readable-stream/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/browserify-sign/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "4.9.2", + "dev": true, + "license": "MIT", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/buffer-more-ints": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/bun-types": { + "version": "1.0.35", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "~20.11.3", + "@types/ws": "~8.5.10" + } + }, + "node_modules/bungie-net-core": { + "version": "2.1.3", + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-me-maybe": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelize": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001600", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0", + "peer": true + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "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/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/cipher-base/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "license": "MIT" + }, + "node_modules/classnames": { + "version": "2.5.1", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/string-width/node_modules/emoji-regex": { + "version": "10.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-truncate/node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/string-width/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/cliui/node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/clsx": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/console-browserify": { + "version": "1.2.0", + "dev": true + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/content-type": { + "version": "1.0.5", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/cookie": { + "version": "0.6.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "license": "MIT" + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/core-js": { + "version": "3.36.1", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-hmac/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/css-to-react-native": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/decko": { + "version": "1.2.0", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/discord-api-types": { + "version": "0.38.47", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.47.tgz", + "integrity": "sha512-XgXQodHQBAE6kfD7kMvVo30863iHX1LHSqNq6MGUTDwIFCCvHva13+rwxyxVXDqudyApMNAd32PGjgVETi5rjA==", + "workspaces": [ + "scripts/actions/documentation" + ] + }, + "node_modules/doctrine": { + "version": "3.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/domain-browser": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4", + "npm": ">=1.2" + } + }, + "node_modules/dompurify": { + "version": "2.4.9", + "dev": true, + "license": "(MPL-2.0 OR Apache-2.0)" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ecdsa-sig-formatter/node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.719", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/elliptic": { + "version": "6.5.5", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.16.0", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.0", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/es6-promise": { + "version": "3.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "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/espree": { + "version": "9.6.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/evp_bytestokey/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/execa": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.19.2", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-xml-parser": { + "version": "5.2.5", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^2.1.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "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": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "dev": true, + "license": "ISC" + }, + "node_modules/foreach": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/form-data": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formidable": { + "version": "2.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/forwarded-parse": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/fresh": { + "version": "0.5.2", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "dev": true, + "license": "BSD-2-Clause", + "peer": true + }, + "node_modules/globals": { + "version": "13.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/hash.js": { + "version": "1.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hexoid": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http2-client": { + "version": "1.3.5", + "dev": true, + "license": "MIT" + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "5.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/husky": { + "version": "9.0.11", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.mjs" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-in-the-middle": { + "version": "1.15.0", + "license": "Apache-2.0", + "dependencies": { + "acorn": "^8.14.0", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, + "node_modules/import-in-the-middle/node_modules/acorn": { + "version": "8.15.0", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/js-levenshtein": { + "version": "1.1.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/json-pointer": { + "version": "0.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "foreach": "^2.0.4" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jwa/node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/jws": { + "version": "3.2.2", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws/node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/lint-staged": { + "version": "15.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "5.3.0", + "commander": "11.1.0", + "debug": "4.3.4", + "execa": "8.0.1", + "lilconfig": "3.0.0", + "listr2": "8.0.1", + "micromatch": "4.0.5", + "pidtree": "0.6.0", + "string-argv": "0.3.2", + "yaml": "2.3.4" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/listr2": { + "version": "8.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.0.0", + "rfdc": "^1.3.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "license": "MIT" + }, + "node_modules/log-update": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^6.2.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^7.0.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lunr": { + "version": "2.3.9", + "dev": true, + "license": "MIT" + }, + "node_modules/mark.js": { + "version": "8.11.1", + "dev": true, + "license": "MIT" + }, + "node_modules/marked": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/md5.js/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/mime": { + "version": "2.6.0", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mobx": { + "version": "6.12.1", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + } + }, + "node_modules/mobx-react": { + "version": "7.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mobx-react-lite": "^3.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.1.0", + "react": "^16.8.0 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/mobx-react-lite": { + "version": "3.4.3", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.1.0", + "react": "^16.8.0 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/module-details-from-path": { + "version": "1.0.4", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch-h2": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "http2-client": "^1.2.5" + }, + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-libs-browser": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + } + }, + "node_modules/node-libs-browser/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/node-libs-browser/node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/node-libs-browser/node_modules/readable-stream/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/node-readfiles": { + "version": "0.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "es6-promise": "^3.2.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/oas-kit-common": { + "version": "1.0.8", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "fast-safe-stringify": "^2.0.7" + } + }, + "node_modules/oas-linter": { + "version": "3.2.2", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@exodus/schemasafe": "^1.0.0-rc.2", + "should": "^13.2.1", + "yaml": "^1.10.0" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-linter/node_modules/yaml": { + "version": "1.10.2", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/oas-resolver": { + "version": "2.5.6", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "node-fetch-h2": "^2.3.0", + "oas-kit-common": "^1.0.8", + "reftools": "^1.1.9", + "yaml": "^1.10.0", + "yargs": "^17.0.1" + }, + "bin": { + "resolve": "resolve.js" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-resolver/node_modules/yaml": { + "version": "1.10.2", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/oas-schema-walker": { + "version": "1.1.5", + "dev": true, + "license": "BSD-3-Clause", + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-validator": { + "version": "5.0.8", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "call-me-maybe": "^1.0.1", + "oas-kit-common": "^1.0.8", + "oas-linter": "^3.2.2", + "oas-resolver": "^2.5.6", + "oas-schema-walker": "^1.1.5", + "reftools": "^1.1.9", + "should": "^13.2.1", + "yaml": "^1.10.0" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/oas-validator/node_modules/yaml": { + "version": "1.10.2", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openapi-sampler": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.7", + "json-pointer": "0.6.2" + } + }, + "node_modules/openapi3-ts": { + "version": "4.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "yaml": "^2.3.4" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/p-limit": { + "version": "3.1.0", + "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", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.7", + "dev": true, + "license": "ISC", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "hash-base": "~3.0", + "pbkdf2": "^3.1.2", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse-asn1/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-browserify": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/pbkdf2/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/perfect-scrollbar": { + "version": "1.5.5", + "dev": true, + "license": "MIT" + }, + "node_modules/pg": { + "version": "8.16.3", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.9.1", + "pg-pool": "^3.10.1", + "pg-protocol": "^1.10.3", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.2.7" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.2.7", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.9.1", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.10.1", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.10.3", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-types/node_modules/postgres-array": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-types/node_modules/postgres-bytea": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/polished": { + "version": "4.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.8" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/prettier-plugin-organize-imports": { + "version": "3.2.4", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@volar/vue-language-plugin-pug": "^1.0.4", + "@volar/vue-typescript": "^1.0.4", + "prettier": ">=2.0", + "typescript": ">=2.9" + }, + "peerDependenciesMeta": { + "@volar/vue-language-plugin-pug": { + "optional": true + }, + "@volar/vue-typescript": { + "optional": true + } + } + }, + "node_modules/prismjs": { + "version": "1.29.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/process": { + "version": "0.11.10", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/prom-client": { + "version": "15.1.1", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.4.0", + "tdigest": "^0.1.1" + }, + "engines": { + "node": "^16 || ^18 || >=20" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "dev": true, + "license": "MIT" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/public-encrypt/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/punycode": { + "version": "1.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.11.0", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randombytes/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/randomfill": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react": { + "version": "17.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "17.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "peerDependencies": { + "react": "17.0.2" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/react-tabs": { + "version": "3.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^1.1.0", + "prop-types": "^15.5.0" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.0-0" + } + }, + "node_modules/readable-stream": { + "version": "1.1.14", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/readable-stream/node_modules/string_decoder": { + "version": "0.10.31", + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/redoc": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@redocly/openapi-core": "^1.0.0-beta.104", + "classnames": "^2.3.1", + "decko": "^1.2.0", + "dompurify": "^2.2.8", + "eventemitter3": "^4.0.7", + "json-pointer": "^0.6.2", + "lunr": "^2.3.9", + "mark.js": "^8.11.1", + "marked": "^4.0.15", + "mobx-react": "^7.2.0", + "openapi-sampler": "^1.3.0", + "path-browserify": "^1.0.1", + "perfect-scrollbar": "^1.5.5", + "polished": "^4.1.3", + "prismjs": "^1.27.0", + "prop-types": "^15.7.2", + "react-tabs": "^3.2.2", + "slugify": "~1.4.7", + "stickyfill": "^1.1.1", + "style-loader": "^3.3.1", + "swagger2openapi": "^7.0.6", + "url-template": "^2.0.8" + }, + "engines": { + "node": ">=6.9", + "npm": ">=3.0.0" + }, + "peerDependencies": { + "core-js": "^3.1.4", + "mobx": "^6.0.4", + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0", + "styled-components": "^4.1.1 || ^5.1.1" + } + }, + "node_modules/redoc-cli": { + "version": "0.13.21", + "dev": true, + "license": "MIT", + "dependencies": { + "boxen": "5.1.2", + "chokidar": "^3.5.1", + "handlebars": "^4.7.7", + "mkdirp": "^1.0.4", + "mobx": "^6.3.2", + "node-libs-browser": "^2.2.1", + "react": "^17.0.1", + "react-dom": "^17.0.1", + "redoc": "2.0.0", + "styled-components": "^5.3.0", + "yargs": "^17.3.1" + }, + "bin": { + "redoc-cli": "index.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/redoc/node_modules/eventemitter3": { + "version": "4.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/redoc/node_modules/path-browserify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/reftools": { + "version": "1.1.9", + "dev": true, + "license": "BSD-3-Clause", + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-in-the-middle": { + "version": "7.5.2", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/require-in-the-middle/node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.11", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "5.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime/node_modules/mimic-fn": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.20.2", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "7.6.0", + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "license": "MIT", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "license": "ISC" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "dev": true, + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/sha.js/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shimmer": { + "version": "1.2.1", + "license": "BSD-2-Clause" + }, + "node_modules/should": { + "version": "13.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "node_modules/should-equal": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "should-type": "^1.4.0" + } + }, + "node_modules/should-format": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "node_modules/should-type": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/should-type-adaptors": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "node_modules/should-util": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/side-channel": { + "version": "1.0.6", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slugify": { + "version": "1.4.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stickyfill": { + "version": "1.1.1", + "dev": true + }, + "node_modules/stream-browserify": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/stream-browserify/node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/stream-browserify/node_modules/readable-stream/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/stream-http": { + "version": "2.8.3", + "dev": true, + "license": "MIT", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/stream-http/node_modules/readable-stream": { + "version": "2.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/stream-http/node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/stream-http/node_modules/readable-stream/node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/string-argv": { + "version": "0.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strnum": { + "version": "2.1.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/style-loader": { + "version": "3.3.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/styled-components": { + "version": "5.3.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/traverse": "^7.4.5", + "@emotion/is-prop-valid": "^1.1.0", + "@emotion/stylis": "^0.8.4", + "@emotion/unitless": "^0.7.4", + "babel-plugin-styled-components": ">= 1.12.0", + "css-to-react-native": "^3.0.0", + "hoist-non-react-statics": "^3.0.0", + "shallowequal": "^1.1.0", + "supports-color": "^5.5.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0", + "react-is": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/styled-components/node_modules/supports-color/node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/superagent": { + "version": "8.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.2", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=6.4.0 <13 || >=14" + } + }, + "node_modules/supertest": { + "version": "6.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "methods": "^1.1.2", + "superagent": "^8.1.2" + }, + "engines": { + "node": ">=6.4.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/swagger2openapi": { + "version": "7.0.8", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "call-me-maybe": "^1.0.1", + "node-fetch": "^2.6.1", + "node-fetch-h2": "^2.3.0", + "node-readfiles": "^0.2.0", + "oas-kit-common": "^1.0.8", + "oas-resolver": "^2.5.6", + "oas-schema-walker": "^1.1.5", + "oas-validator": "^5.0.8", + "reftools": "^1.1.9", + "yaml": "^1.10.0", + "yargs": "^17.0.1" + }, + "bin": { + "boast": "boast.js", + "oas-validate": "oas-validate.js", + "swagger2openapi": "swagger2openapi.js" + }, + "funding": { + "url": "https://github.com/Mermade/oas-kit?sponsor=1" + } + }, + "node_modules/swagger2openapi/node_modules/yaml": { + "version": "1.10.2", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/synckit": { + "version": "0.8.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/synckit/node_modules/tslib": { + "version": "2.6.2", + "dev": true, + "license": "0BSD" + }, + "node_modules/tapable": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tdigest": { + "version": "0.1.2", + "license": "MIT", + "dependencies": { + "bintrees": "1.0.2" + } + }, + "node_modules/terser": { + "version": "5.30.0", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/terser/node_modules/source-map-support": { + "version": "0.5.21", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/timers-browserify": { + "version": "2.0.12", + "dev": true, + "license": "MIT", + "dependencies": { + "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-arraybuffer": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tslib": { + "version": "2.7.0", + "license": "0BSD" + }, + "node_modules/tty-browserify": { + "version": "0.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/url": { + "version": "0.11.3", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.11.2" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/url-template": { + "version": "2.0.8", + "dev": true, + "license": "BSD" + }, + "node_modules/url/node_modules/qs": { + "version": "6.12.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/util": { + "version": "0.11.1", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "dev": true, + "license": "ISC" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/watchpack": { + "version": "2.4.1", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/webpack": { + "version": "5.91.0", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.16.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "9.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi/node_modules/string-width/node_modules/emoji-regex": { + "version": "10.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.3.4", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 14" + } + }, + "node_modules/yaml-ast-parser": { + "version": "0.0.43", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/yargs": { + "version": "17.7.2", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.22.4", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/package.json b/package.json index 73f5caec..b7b7ce81 100644 --- a/package.json +++ b/package.json @@ -15,14 +15,15 @@ "scripts": { "prepare": "husky", "dev": "bun --watch ./src/index.ts", - "typecheck": "tsc --noEmit", - "lint": "eslint . --ext .ts,.json", + "typecheck": "eslint . --ext .ts", + "lint": "eslint . --ext .ts", "format": "prettier '**/*.{ts,json}'", "docs": "bun run ./open-api/generate.ts", + "discord:sync-commands": "bun run ./scripts/discord/sync-commands.ts", "compile": "bun build --compile --sourcemap ./src/index.ts --outfile $1" }, "lint-staged": { - "*.{ts,json}": [ + "*.ts": [ "eslint --fix" ], "*.js": "eslint --cache --fix" @@ -57,6 +58,7 @@ "amqplib": "^0.10.3", "bungie-net-core": "2.1.3", "compression": "^1.7.4", + "discord-api-types": "^0.38.47", "express": "^4.18.2", "jsonwebtoken": "^9.0.2", "pg": "^8.16.3", @@ -104,18 +106,20 @@ "browser": true, "es2021": true }, - "extends": [ - "eslint:recommended", - "prettier", - "plugin:@typescript-eslint/recommended" - ], "parserOptions": { "ecmaVersion": "latest", - "sourceType": "module" + "sourceType": "module", + "project": "./tsconfig.json" }, "plugins": [ "@typescript-eslint" ], + "extends": [ + "eslint:recommended", + "prettier", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-type-checked" + ], "rules": { "no-unused-vars": "off", "no-case-declarations": "off", @@ -125,7 +129,20 @@ { "argsIgnorePattern": "^_" } - ] + ], + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/no-unsafe-argument": "off", + "@typescript-eslint/no-unsafe-return": "off", + "@typescript-eslint/no-unsafe-enum-comparison": "off", + "@typescript-eslint/no-misused-promises": "off", + "@typescript-eslint/require-await": "off", + "@typescript-eslint/no-namespace": "off", + "@typescript-eslint/restrict-template-expressions": "off", + "@typescript-eslint/no-floating-promises": "off", + "@typescript-eslint/unbound-method": "off", + "@typescript-eslint/no-explicit-any": "off", + "no-constant-condition": "off" }, "overrides": [ { diff --git a/scripts/discord/sync-commands.ts b/scripts/discord/sync-commands.ts new file mode 100644 index 00000000..f4c7eecf --- /dev/null +++ b/scripts/discord/sync-commands.ts @@ -0,0 +1,87 @@ +import { deriveDiscordCommandOptions, collectDiscordExposedRoutes } from "@/integrations/discord/command-registry" +import { router } from "@/routes/index" +import { ApplicationCommandOptionType, ApplicationCommandType } from "discord-api-types/v10" + +type DiscordCommandPayload = { + name: string + description: string + type: ApplicationCommandType.ChatInput + options?: { + type: + | ApplicationCommandOptionType.String + | ApplicationCommandOptionType.Integer + | ApplicationCommandOptionType.Boolean + | ApplicationCommandOptionType.Number + name: string + description: string + required: boolean + }[] +} + +const getEnv = (key: string) => { + const value = process.env[key]?.trim() + if (!value) { + throw new Error(`${key} is required`) + } + return value +} + +const toPayload = (): DiscordCommandPayload[] => { + const entries = [...collectDiscordExposedRoutes(router).values()] + return entries + .map(entry => ({ + name: entry.commandName.toLowerCase().slice(0, 32), + description: (entry.description || `Run ${entry.commandName}`).slice(0, 100), + type: ApplicationCommandType.ChatInput as const, + options: deriveDiscordCommandOptions(entry.route) + })) + .sort((a, b) => a.name.localeCompare(b.name)) +} + +const applicationId = getEnv("DISCORD_APPLICATION_ID") +const botToken = getEnv("DISCORD_BOT_TOKEN") +const guildId = process.env.DISCORD_GUILD_ID?.trim() +const dryRun = process.env.DISCORD_SYNC_DRY_RUN === "true" + +const endpoint = guildId + ? `https://discord.com/api/v10/applications/${applicationId}/guilds/${guildId}/commands` + : `https://discord.com/api/v10/applications/${applicationId}/commands` + +const payload = toPayload() + +if (dryRun) { + console.log( + JSON.stringify( + { + target: guildId ? `guild:${guildId}` : "global", + endpoint, + commands: payload + }, + null, + 2 + ) + ) + process.exit(0) +} + +try { + const response = await fetch(endpoint, { + method: "PUT", + headers: { + Authorization: `Bot ${botToken}`, + "Content-Type": "application/json" + }, + body: JSON.stringify(payload) + }) + + if (!response.ok) { + const details = await response.text() + throw new Error(`Discord command sync failed (${response.status}): ${details}`) + } + + console.log(`Synced ${payload.length} Discord command(s) to ${guildId ? "guild" : "global"} scope.`) + process.exit(0) +} catch (error) { + console.error(error instanceof Error ? error.message : String(error)) + process.exit(1) +} diff --git a/src/auth/admin.ts b/src/auth/admin.ts index d1f95d58..49e20b34 100644 --- a/src/auth/admin.ts +++ b/src/auth/admin.ts @@ -1,8 +1,6 @@ import { ErrorCode } from "@/schema/errors/ErrorCode" import { InsufficientPermissionsError } from "@/schema/errors/InsufficientPermissionsError" import { RequestHandler } from "express" -import jwt from "jsonwebtoken" -import { zJWTAuthFormat } from "./jwt" const error = (): InsufficientPermissionsError => ({ minted: new Date(), @@ -14,24 +12,9 @@ const error = (): InsufficientPermissionsError => ({ }) export const adminProtected: RequestHandler = (req, res, next) => { - const authHeader = req.headers["authorization"] - const [format, token] = authHeader ? authHeader.split(" ") : ["", ""] - - if (format !== "Bearer") { - res.status(403).json(error()) + if (req.auth?.isAdmin) { + next() return } - - jwt.verify(token, process.env.JWT_SECRET!, (err, result) => { - if (err) { - res.status(403).json(error()) - } else { - const data = zJWTAuthFormat.parse(result) - if (data.isAdmin) { - next() - } else { - res.status(403).json(error()) - } - } - }) + res.status(403).json(error()) } diff --git a/src/auth/api-keys.ts b/src/auth/api-keys.ts index cc6873a0..7220f799 100644 --- a/src/auth/api-keys.ts +++ b/src/auth/api-keys.ts @@ -12,7 +12,7 @@ const KeySchema = z.object({ key: z.string() }) -const apiKeys = file(process.env.API_KEYS_PATH!, { type: "application/json" }) +const apiKeys = file(process.env.API_KEYS_PATH, { type: "application/json" }) .json() .then( ( diff --git a/src/auth/discord-context.ts b/src/auth/discord-context.ts new file mode 100644 index 00000000..cc7d636e --- /dev/null +++ b/src/auth/discord-context.ts @@ -0,0 +1,36 @@ +import { verifyDiscordInvocationContext } from "@/integrations/discord/context-jwt" +import { ErrorCode } from "@/schema/errors/ErrorCode" +import { RequestHandler } from "express" + +const DISCORD_AUTH_SCHEME = "Discord" + +const extractDiscordContextToken = (authorizationHeader?: string) => { + if (!authorizationHeader) return null + const [scheme, token] = authorizationHeader.trim().split(" ") + if (scheme !== DISCORD_AUTH_SCHEME) return null + return token || null +} + +export const attachDiscordContext: RequestHandler = (req, res, next) => { + const token = extractDiscordContextToken(req.headers.authorization) + if (!token) { + req.discord = undefined + next() + return + } + + try { + req.discord = verifyDiscordInvocationContext(token) + next() + } catch { + res.status(401).json({ + minted: new Date(), + success: false, + code: ErrorCode.InvalidDiscordAuthError, + error: { + message: "Invalid Discord context token" + } + }) + } +} + diff --git a/src/auth/express-auth-context.ts b/src/auth/express-auth-context.ts new file mode 100644 index 00000000..30620fc0 --- /dev/null +++ b/src/auth/express-auth-context.ts @@ -0,0 +1,12 @@ +import type { JWTAuthContext } from "./jwt" + +declare global { + namespace Express { + interface Request { + auth?: JWTAuthContext + } + } +} + +export {} + diff --git a/src/auth/express-discord-context.ts b/src/auth/express-discord-context.ts new file mode 100644 index 00000000..33a66fc2 --- /dev/null +++ b/src/auth/express-discord-context.ts @@ -0,0 +1,12 @@ +import type { DiscordInvocationContext } from "@/integrations/discord/context-jwt" + +declare global { + namespace Express { + interface Request { + discord?: DiscordInvocationContext + } + } +} + +export {} + diff --git a/src/auth/jwt.ts b/src/auth/jwt.ts index 5620b025..aac0f35b 100644 --- a/src/auth/jwt.ts +++ b/src/auth/jwt.ts @@ -7,7 +7,9 @@ export const zJWTAuthFormat = z.object({ destinyMembershipIds: z.array(z.string()) }) -export const generateJWT = (data: z.infer, expiresIn: number) => { +export type JWTAuthContext = z.infer + +export const generateJWT = (data: JWTAuthContext, expiresIn: number) => { return jwt.sign(data, process.env.JWT_SECRET, { expiresIn }) diff --git a/src/auth/protected-resource.ts b/src/auth/protected-resource.ts index fe06f562..df411973 100644 --- a/src/auth/protected-resource.ts +++ b/src/auth/protected-resource.ts @@ -1,32 +1,16 @@ import { Logger } from "@/lib/utils/logging" -import jwt from "jsonwebtoken" -import { zJWTAuthFormat } from "./jwt" +import { JWTAuthContext } from "./jwt" const logger = new Logger("API_AUTH_SERVICE") export const canAccessProtectedResource = async ( destinyMembershipId: string | bigint, - authHeader: string + auth: JWTAuthContext | undefined ) => { - if (!authHeader) return false - - const [format, token] = authHeader ? authHeader.split(" ") : ["", ""] - if (format !== "Bearer" || !token) return false + if (!auth) return false try { - return await new Promise(resolve => - jwt.verify(token, process.env.JWT_SECRET!, (err, result) => { - if (err) { - resolve(false) - } else { - const data = zJWTAuthFormat.parse(result) - resolve( - data.isAdmin || - data.destinyMembershipIds.includes(String(destinyMembershipId)) - ) - } - }) - ) + return auth.isAdmin || auth.destinyMembershipIds.includes(String(destinyMembershipId)) } catch (err) { logger.warn( "JWT_VERIFICATION_FAILED", diff --git a/src/auth/user-context.ts b/src/auth/user-context.ts new file mode 100644 index 00000000..e620b075 --- /dev/null +++ b/src/auth/user-context.ts @@ -0,0 +1,29 @@ +import { RequestHandler } from "express" +import jwt from "jsonwebtoken" +import { zJWTAuthFormat } from "./jwt" + +const BEARER_AUTH_SCHEME = "Bearer" + +const extractBearerToken = (authorizationHeader?: string) => { + if (!authorizationHeader) return null + const [scheme, token] = authorizationHeader.trim().split(" ") + if (scheme !== BEARER_AUTH_SCHEME) return null + return token || null +} + +export const attachUserAuth: RequestHandler = (req, _res, next) => { + const token = extractBearerToken(req.headers.authorization) + if (!token) { + req.auth = undefined + next() + return + } + + try { + const decoded = jwt.verify(token, process.env.JWT_SECRET) + req.auth = zJWTAuthFormat.parse(decoded) + } catch (error) { + req.auth = undefined + } + next() +} diff --git a/src/core/RaidHubRoute.ts b/src/core/RaidHubRoute.ts index d5c8763a..2f814d95 100644 --- a/src/core/RaidHubRoute.ts +++ b/src/core/RaidHubRoute.ts @@ -282,6 +282,60 @@ export class RaidHubRoute< return this.parent ? this.parent.getFullPath(this) : "/" } + getDerivedRouteId() { + const normalizedPath = this.getFullPath() + .replace(/\/+/g, "/") + .replace(/^\/|\/$/g, "") + .replace(/:(\w+)/g, "{$1}") + return `${this.method.toUpperCase()} ${normalizedPath || "/"}` + } + + async invoke( + req: { + params?: unknown + query?: unknown + body?: unknown + headers?: IncomingHttpHeaders + auth?: import("@/auth/jwt").JWTAuthContext + discord?: import("@/integrations/discord/context-jwt").DiscordInvocationContext + } = {}, + after?: (callback: () => Promise) => void + ) { + const callbacks: (() => Promise)[] = [] + const result = await this.handler( + { + params: this.paramsSchema?.parse(req.params) ?? {}, + query: this.querySchema?.parse(req.query ?? {}) ?? {}, + body: this.bodySchema?.parse(req.body) ?? {}, + headers: req.headers ?? {}, + auth: req.auth, + discord: req.discord + }, + callback => { + callbacks.push(callback) + after?.(callback) + } + ) + + for (const callback of callbacks) { + try { + await callback() + } catch (err) { + logger.error( + "ROUTE_AFTER_CALLBACK_ERROR", + err instanceof Error ? err : new Error(String(err)), + { + path: this.getFullPath(), + method: this.method.toUpperCase(), + mode: "invoke" + } + ) + } + } + + return result + } + deprecatedCopy() { return new RaidHubRoute({ isDeprecated: true, diff --git a/src/core/RaidHubRouterTypes.ts b/src/core/RaidHubRouterTypes.ts index d6f8d06b..ab5abb16 100644 --- a/src/core/RaidHubRouterTypes.ts +++ b/src/core/RaidHubRouterTypes.ts @@ -1,3 +1,5 @@ +import type { JWTAuthContext } from "@/auth/jwt" +import type { DiscordInvocationContext } from "@/integrations/discord/context-jwt" import { ErrorCode } from "@/schema/errors/ErrorCode" import { RouteConfig } from "@asteasolutions/zod-to-openapi" import { Router } from "express" @@ -36,6 +38,8 @@ export type RaidHubHandler< query: z.output body: z.output headers: IncomingHttpHeaders + auth?: JWTAuthContext + discord?: DiscordInvocationContext }, after: (callback: () => Promise) => void ) => Promise> diff --git a/src/index.ts b/src/index.ts index 2f3844c1..59a2f001 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,9 @@ import compression from "compression" import express, { Router, static as expressStatic, json } from "express" import path from "path" import { verifyApiKey } from "./auth/api-keys" +import { attachDiscordContext } from "./auth/discord-context" +import { attachUserAuth } from "./auth/user-context" +import { discordInteractionsRouter } from "./integrations/discord/interactions" import { servePrometheus } from "./integrations/prometheus/server" import { Logger } from "./lib/utils/logging" import { errorHandler } from "./middleware/error-handler" @@ -43,8 +46,19 @@ app.options("*", (req, res) => { res.sendStatus(204) }) +// Discord validates signatures against raw request bytes. +app.use("/integrations/discord", express.raw({ type: "*/*" }), discordInteractionsRouter) + // parse incoming request body with json, apply the router, handle any uncaught errors -app.use(verifyApiKey, json(), compression(), router.mountable, errorHandler) +app.use( + verifyApiKey, + attachUserAuth, + attachDiscordContext, + json(), + compression(), + router.mountable, + errorHandler +) // Start the server app.listen(port, () => { diff --git a/src/integrations/discord/command-registry.ts b/src/integrations/discord/command-registry.ts new file mode 100644 index 00000000..3855cf1e --- /dev/null +++ b/src/integrations/discord/command-registry.ts @@ -0,0 +1,244 @@ +import { RaidHubRoute } from "@/core/RaidHubRoute" +import { RaidHubRouter } from "@/core/RaidHubRouter" +import { IRaidHubRoute } from "@/core/RaidHubRouterTypes" +import { instanceRoute } from "@/routes/instance" +import { playerSearchRoute } from "@/routes/player/search" +import { ApplicationCommandOptionType } from "discord-api-types/v10" +import { z } from "zod" +import { signDiscordInvocationContext } from "./context-jwt" +import { DiscordApiStyleRequest, DiscordInteraction, DiscordInteractionDataOption } from "./types" + +type AnyRaidHubRoute = RaidHubRoute< + "get" | "post" | "patch" | "put" | "delete", + z.ZodTypeAny, + any, + any, + any, + any +> + +const discordEnabledRoutes = new Set([instanceRoute, playerSearchRoute]) + +export type DiscordExposedRoute = { + commandName: string + route: AnyRaidHubRoute + description: string + routeId: string +} + +const snakeCase = (input: string) => + input + .replace(/([a-z0-9])([A-Z])/g, "$1_$2") + .replace(/[\s-]+/g, "_") + .toLowerCase() + +const commandNameFromPath = (fullPath: string) => { + const segments = fullPath + .split("/") + .filter(Boolean) + .filter(segment => !segment.startsWith(":")) + .map(segment => segment.replace(/[^a-zA-Z0-9_-]/g, "").toLowerCase()) + .filter(Boolean) + return (segments.join("-") || "command").slice(0, 32) +} + +const commandDescriptionFromRoute = (description: string, commandName: string) => { + const normalized = description.replace(/\s+/g, " ").trim() + if (!normalized) return `Run ${commandName}`.slice(0, 100) + return normalized.slice(0, 100) +} + +const flattenRoutes = (node: IRaidHubRoute): AnyRaidHubRoute[] => { + if (node instanceof RaidHubRoute) return [node as AnyRaidHubRoute] + if (node instanceof RaidHubRouter) { + return node.routes.flatMap(({ route }) => + Array.isArray(route) + ? route.flatMap(child => flattenRoutes(child)) + : flattenRoutes(route) + ) + } + return [] +} + +export const collectDiscordExposedRoutes = ( + root: RaidHubRouter +): Map => { + const routes = flattenRoutes(root) + const exposed = routes + .map(route => ({ + route, + routeId: route.getDerivedRouteId() + })) + .filter(item => discordEnabledRoutes.has(item.route)) + + const byCommand = new Map() + for (const { route, routeId } of exposed) { + const commandName = commandNameFromPath(route.getFullPath()) + byCommand.set(commandName, { + commandName, + route, + routeId, + description: commandDescriptionFromRoute(route.description, commandName) + }) + } + return byCommand +} + +const flattenCommandOptions = (options: DiscordInteractionDataOption[] = []) => { + const flattened: [string, string | number | boolean][] = [] + for (const option of options ?? []) { + if (typeof option.value !== "undefined") { + flattened.push([option.name, option.value]) + } + if (option.options && option.options.length > 0) { + flattened.push(...flattenCommandOptions(option.options)) + } + } + return flattened +} + +const getCommandOptionMap = (interaction: DiscordInteraction) => + Object.fromEntries(flattenCommandOptions(interaction.data?.options)) + +const camelCase = (value: string) => + value.replace(/_([a-z])/g, (_, letter: string) => letter.toUpperCase()) + +const getZodObjectShape = (schema: z.ZodTypeAny | null): Record => { + if (!(schema instanceof z.ZodObject)) return {} + return schema.shape as Record +} + +const getRouteShapes = (route: AnyRaidHubRoute) => ({ + params: getZodObjectShape(route.paramsSchema), + query: getZodObjectShape(route.querySchema), + body: getZodObjectShape(route.bodySchema) +}) + +const inferOptionTarget = ( + route: AnyRaidHubRoute, + field: string +): "params" | "query" | "body" => { + const shapes = getRouteShapes(route) + if (field in shapes.params) return "params" + if (field in shapes.query) return "query" + return "body" +} + +export const buildRouteInvocationRequest = ( + interaction: DiscordInteraction, + exposedRoute: DiscordExposedRoute, + headers: Record = {} +): DiscordApiStyleRequest => { + const rawOptions = getCommandOptionMap(interaction) + const params: Record = {} + const query: Record = {} + const body: Record = {} + + for (const [optionName, value] of Object.entries(rawOptions)) { + const field = camelCase(optionName) + const target = inferOptionTarget(exposedRoute.route, field) + + if (target === "params") params[field] = value + else if (target === "query") query[field] = value + else body[field] = value + } + + const contextJwt = signDiscordInvocationContext({ + interactionId: interaction.id, + commandName: exposedRoute.commandName, + routeId: exposedRoute.routeId, + userId: interaction.member?.user?.id ?? "", + guildId: interaction.guild_id, + channelId: interaction.channel_id + }) + + return { + params, + query, + body: Object.keys(body).length > 0 ? body : null, + headers: { + authorization: `Discord ${contextJwt}`, + ...headers + } + } +} + +export const deriveDiscordOptionNames = (route: AnyRaidHubRoute) => { + return deriveDiscordCommandOptions(route).map(option => option.name) +} + +type DiscordApplicationCommandOption = { + type: + | ApplicationCommandOptionType.String + | ApplicationCommandOptionType.Integer + | ApplicationCommandOptionType.Boolean + | ApplicationCommandOptionType.Number + name: string + description: string + required: boolean +} + +const inferDiscordOptionType = ( + schema: z.ZodTypeAny +): + | ApplicationCommandOptionType.String + | ApplicationCommandOptionType.Integer + | ApplicationCommandOptionType.Boolean + | ApplicationCommandOptionType.Number => { + let current = schema + while (true) { + if (current instanceof z.ZodOptional || current instanceof z.ZodNullable) { + current = current.unwrap() as z.ZodTypeAny + continue + } + if (current instanceof z.ZodDefault || current instanceof z.ZodCatch) { + current = current._def.innerType as z.ZodTypeAny + continue + } + if (current instanceof z.ZodEffects) { + current = current.innerType() + continue + } + break + } + + if (current instanceof z.ZodBoolean) return ApplicationCommandOptionType.Boolean + if (current instanceof z.ZodNumber) { + return current.isInt + ? ApplicationCommandOptionType.Integer + : ApplicationCommandOptionType.Number + } + if (current instanceof z.ZodNativeEnum) { + const values = Object.values(current.enum as Record) + if (values.some(value => typeof value === "number")) { + return ApplicationCommandOptionType.Integer + } + } + return ApplicationCommandOptionType.String +} + +export const deriveDiscordCommandOptions = ( + route: AnyRaidHubRoute +): DiscordApplicationCommandOption[] => { + const shapes = getRouteShapes(route) + const options = new Map() + + const addShapeOptions = (shape: Record) => { + for (const [key, schema] of Object.entries(shape)) { + const optionName = snakeCase(key).slice(0, 32) + if (options.has(optionName)) continue + options.set(optionName, { + type: inferDiscordOptionType(schema), + name: optionName, + description: `Value for ${optionName}`.slice(0, 100), + required: false + }) + } + } + + addShapeOptions(shapes.params) + addShapeOptions(shapes.query) + addShapeOptions(shapes.body) + + return [...options.values()] +} diff --git a/src/integrations/discord/context-jwt.ts b/src/integrations/discord/context-jwt.ts new file mode 100644 index 00000000..50c0c868 --- /dev/null +++ b/src/integrations/discord/context-jwt.ts @@ -0,0 +1,24 @@ +import jwt from "jsonwebtoken" +import { z } from "zod" + +export const zDiscordInvocationContext = z.object({ + interactionId: z.string(), + commandName: z.string(), + userId: z.string(), + guildId: z.string().optional(), + channelId: z.string().optional(), + routeId: z.string() +}) + +export type DiscordInvocationContext = z.infer + +export const signDiscordInvocationContext = (context: DiscordInvocationContext) => { + return jwt.sign(context, process.env.JWT_SECRET, { + expiresIn: 120 + }) +} + +export const verifyDiscordInvocationContext = (token: string) => { + const decoded = jwt.verify(token, process.env.JWT_SECRET) + return zDiscordInvocationContext.parse(decoded) +} diff --git a/src/integrations/discord/interactions.ts b/src/integrations/discord/interactions.ts new file mode 100644 index 00000000..ca476282 --- /dev/null +++ b/src/integrations/discord/interactions.ts @@ -0,0 +1,208 @@ +import { Router } from "express" +import { createPublicKey, verify } from "crypto" +import { InteractionResponseType, InteractionType } from "discord-api-types/v10" +import { Logger } from "@/lib/utils/logging" +import { router as rootRouter } from "@/routes/index" +import { ErrorCode } from "@/schema/errors/ErrorCode" +import { + buildRouteInvocationRequest, + collectDiscordExposedRoutes, + deriveDiscordOptionNames +} from "./command-registry" +import { + mapDiscordComponentInteraction, + mapDiscordKnownError, + mapDiscordSuccess +} from "./response-registry" +import { DiscordComponentsV2Response, DiscordInteraction } from "./types" + +const SIGNATURE_WINDOW_MS = 5 * 60 * 1000 +const logger = new Logger("DISCORD_INTERACTIONS") + +const toDiscordPublicKey = (hex: string) => { + const raw = Buffer.from(hex, "hex") + const derHeader = Buffer.from("302a300506032b6570032100", "hex") + return createPublicKey({ + key: Buffer.concat([derHeader, raw]), + format: "der", + type: "spki" + }) +} + +const verifyDiscordSignature = (args: { + timestamp: string + signatureHex: string + rawBody: Buffer +}): boolean => { + const publicKeyHex = process.env.DISCORD_PUBLIC_KEY + if (!publicKeyHex) return false + + const timestampMs = Number(args.timestamp) * 1000 + if (!Number.isFinite(timestampMs) || Math.abs(Date.now() - timestampMs) > SIGNATURE_WINDOW_MS) { + return false + } + + const message = Buffer.concat([Buffer.from(args.timestamp), args.rawBody]) + const signature = Buffer.from(args.signatureHex, "hex") + return verify(null, message, toDiscordPublicKey(publicKeyHex), signature) +} + +const toComponentsResponse = (content: string): DiscordComponentsV2Response => ({ + type: InteractionResponseType.ChannelMessageWithSource, + data: { + content + } +}) + +const interactionAppId = () => { + const value = process.env.DISCORD_APPLICATION_ID?.trim() + if (!value) throw new Error("DISCORD_APPLICATION_ID is required for deferred command responses") + return value +} + +const patchOriginalInteractionResponse = async ( + interaction: DiscordInteraction, + message: DiscordComponentsV2Response["data"] +) => { + const applicationId = interaction.application_id ?? interactionAppId() + const response = await fetch( + `https://discord.com/api/v10/webhooks/${applicationId}/${interaction.token}/messages/@original`, + { + method: "PATCH", + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(message) + } + ) + + if (!response.ok) { + const detail = await response.text() + throw new Error(`Failed to update interaction response (${response.status}): ${detail}`) + } +} + +export const discordInteractionsRouter = Router() + +discordInteractionsRouter.post("/interactions", async (req, res) => { + const signature = req.header("X-Signature-Ed25519") + const timestamp = req.header("X-Signature-Timestamp") + const rawBody = Buffer.isBuffer(req.body) ? req.body : Buffer.from("") + + if (!signature || !timestamp || !verifyDiscordSignature({ signatureHex: signature, timestamp, rawBody })) { + res.status(401).json({ + minted: new Date(), + success: false, + code: ErrorCode.InvalidDiscordAuthError, + error: { + message: "Invalid Discord signature" + } + }) + return + } + + const interaction = JSON.parse(rawBody.toString("utf8")) as DiscordInteraction + if (interaction.type === InteractionType.Ping) { + res.status(200).json({ type: InteractionResponseType.Pong }) + return + } + + if (interaction.type === InteractionType.MessageComponent) { + const updated = mapDiscordComponentInteraction(interaction) + if (!updated) { + res.status(400).json(toComponentsResponse("Unsupported interaction component")) + return + } + res.status(200).json({ + type: InteractionResponseType.UpdateMessage, + data: updated + }) + return + } + + if (interaction.type !== InteractionType.ApplicationCommand || !interaction.data?.name) { + res.status(400).json(toComponentsResponse("Unsupported interaction type")) + return + } + + const commandMap = collectDiscordExposedRoutes(rootRouter) + const binding = commandMap.get(interaction.data.name) + + if (!binding) { + res.status(200).json(toComponentsResponse("This command is not enabled yet.")) + return + } + + const processCommand = async () => { + const apiRequest = buildRouteInvocationRequest(interaction, binding) + let result: Awaited> + try { + result = await binding.route.invoke(apiRequest) + } catch (err) { + logger.error( + "DISCORD_ROUTE_INVOKE_FAILED", + err instanceof Error ? err : new Error(String(err)), + { + command: binding.commandName, + route_id: binding.routeId + } + ) + await patchOriginalInteractionResponse( + interaction, + toComponentsResponse(`Execution failed for \`${binding.commandName}\`.`).data + ) + return + } + + if (result.success) { + const mapped = mapDiscordSuccess(binding, result) + if (mapped) { + await patchOriginalInteractionResponse(interaction, mapped) + return + } + await patchOriginalInteractionResponse( + interaction, + toComponentsResponse(`Success for \`${binding.commandName}\` (${binding.routeId})`).data + ) + return + } + + const mappedError = mapDiscordKnownError(binding, result) + if (mappedError) { + await patchOriginalInteractionResponse(interaction, mappedError) + return + } + await patchOriginalInteractionResponse( + interaction, + toComponentsResponse(`Request failed with \`${result.code}\` while running \`${binding.commandName}\`.`).data + ) + } + + res.status(200).json({ + type: InteractionResponseType.DeferredChannelMessageWithSource + }) + + void processCommand().catch(async () => { + try { + const knownOptions = deriveDiscordOptionNames(binding.route) + const receivedOptions = (interaction.data?.options ?? []) + .map(option => option.name) + .join(", ") + await patchOriginalInteractionResponse( + interaction, + toComponentsResponse( + `Unable to run \`${binding.commandName}\`. Expected options: ${knownOptions.join(", ")}. Received: ${receivedOptions || "none"}.` + ).data + ) + } catch (err) { + logger.error( + "DISCORD_COMMAND_RESPONSE_FAILED", + err instanceof Error ? err : new Error(String(err)), + { + command: binding.commandName, + route_id: binding.routeId + } + ) + } + }) +}) diff --git a/src/integrations/discord/message-builders.ts b/src/integrations/discord/message-builders.ts new file mode 100644 index 00000000..ba626100 --- /dev/null +++ b/src/integrations/discord/message-builders.ts @@ -0,0 +1,28 @@ +import { DiscordComponentsV2Response } from "./types" + +type DiscordEmbedField = { + name: string + value: string + inline?: boolean +} + +type DiscordEmbed = { + title?: string + description?: string + fields?: DiscordEmbedField[] + color?: number + timestamp?: string +} + +type DiscordMessageData = DiscordComponentsV2Response["data"] & { + embeds?: DiscordEmbed[] +} + +export const buildDiscordContentMessage = (content: string): DiscordMessageData => ({ + content +}) + +export const buildDiscordEmbedMessage = (embed: DiscordEmbed): DiscordMessageData => ({ + embeds: [embed] +}) + diff --git a/src/integrations/discord/response-registry.ts b/src/integrations/discord/response-registry.ts new file mode 100644 index 00000000..52184475 --- /dev/null +++ b/src/integrations/discord/response-registry.ts @@ -0,0 +1,205 @@ +import { buildDiscordContentMessage, buildDiscordEmbedMessage } from "./message-builders" +import { DiscordExposedRoute } from "./command-registry" +import { DiscordComponentsV2Response, DiscordInteraction } from "./types" +import { ButtonStyle, ComponentType, InteractionType } from "discord-api-types/v10" +import { playerSearchRoute } from "@/routes/player/search" +import { ErrorCode } from "@/schema/errors/ErrorCode" +import { zInstanceExtended } from "@/schema/components/InstanceExtended" +import { randomUUID } from "crypto" +import { z } from "zod" + +type DiscordInvocationSuccess = { success: true; response: unknown } +type DiscordInvocationFailure = { success: false; code: string; error: unknown } + +type DiscordResponseMapper = { + mapSuccess?: (response: unknown) => DiscordComponentsV2Response["data"] + mapKnownErrors?: Partial DiscordComponentsV2Response["data"]>> +} + +const formatDuration = (seconds: number) => { + const h = Math.floor(seconds / 3600) + const m = Math.floor((seconds % 3600) / 60) + const s = seconds % 60 + return `${h}h ${m}m ${s}s` +} + +const formatInstanceDiscordSummary = (response: z.infer) => + buildDiscordEmbedMessage({ + title: response.metadata.activityName, + description: `Instance \`${response.instanceId}\``, + color: 0x5865f2, + fields: [ + { name: "Version", value: response.metadata.versionName, inline: true }, + { name: "Players", value: String(response.playerCount), inline: true }, + { name: "Duration", value: formatDuration(response.duration), inline: true }, + { name: "Completed", value: response.completed ? "Yes" : "No", inline: true }, + { name: "Fresh", value: response.fresh ? "Yes" : "No", inline: true }, + { name: "Flawless", value: response.flawless ? "Yes" : "No", inline: true }, + { + name: "Completed At", + value: + response.dateCompleted instanceof Date + ? response.dateCompleted.toISOString() + : String(response.dateCompleted), + inline: false + } + ] + }) + +type PlayerSearchResponse = z.infer +type PlayerSearchPagerState = { + createdAt: number + response: PlayerSearchResponse +} +const PLAYER_SEARCH_PAGE_SIZE = 5 +const PLAYER_SEARCH_PAGER_TTL_MS = 10 * 60 * 1000 +const PLAYER_SEARCH_PAGER_PREFIX = "ps" +const playerSearchPager = new Map() + +const putPlayerSearchPagerState = (response: PlayerSearchResponse) => { + const id = randomUUID().replace(/-/g, "").slice(0, 16) + playerSearchPager.set(id, { + createdAt: Date.now(), + response + }) + return id +} + +const getPlayerSearchPagerState = (id: string) => { + const state = playerSearchPager.get(id) + if (!state) return null + if (Date.now() - state.createdAt > PLAYER_SEARCH_PAGER_TTL_MS) { + playerSearchPager.delete(id) + return null + } + return state +} + +const clamp = (value: number, min: number, max: number) => Math.max(min, Math.min(max, value)) + +const formatPlayerName = (player: PlayerSearchResponse["results"][number]) => { + if (player.bungieGlobalDisplayName) { + const code = player.bungieGlobalDisplayNameCode ? `#${player.bungieGlobalDisplayNameCode}` : "" + return `${player.bungieGlobalDisplayName}${code}` + } + return player.displayName ?? "Unknown Player" +} + +const parsePlayerSearchButtonId = (customId: string) => { + const parts = customId.split(":") + if (parts.length !== 3) return null + if (parts[0] !== PLAYER_SEARCH_PAGER_PREFIX) return null + const page = Number(parts[2]) + if (!Number.isInteger(page)) return null + return { + stateId: parts[1], + page + } +} + +const renderPlayerSearchSummary = (response: PlayerSearchResponse, stateId: string, page: number) => { + if (response.results.length === 0 || page < 0) { + return buildDiscordContentMessage(`No players found for \`${response.params.query}\`.`) + } + + const totalPages = Math.max(1, Math.ceil(response.results.length / PLAYER_SEARCH_PAGE_SIZE)) + const currentPage = clamp(page, 0, totalPages - 1) + const start = currentPage * PLAYER_SEARCH_PAGE_SIZE + const preview = response.results.slice(start, start + PLAYER_SEARCH_PAGE_SIZE) + const lines = preview.map((player, idx) => { + const membershipType = player.membershipType === null ? "unknown" : String(player.membershipType) + return `${start + idx + 1}. **${formatPlayerName(player)}** (\`${player.membershipId}\`, type ${membershipType})` + }) + + const message = buildDiscordEmbedMessage({ + title: "Player Search Results", + description: + `Query: \`${response.params.query}\`\n` + + `Page ${currentPage + 1}/${totalPages} - showing ${preview.length}/${response.results.length} result(s).`, + color: 0x57f287, + fields: [ + { + name: "Matches", + value: lines.join("\n"), + inline: false + } + ] + }) + + return { + ...message, + components: [ + { + type: ComponentType.ActionRow, + components: [ + { + type: ComponentType.Button, + style: ButtonStyle.Secondary, + custom_id: `${PLAYER_SEARCH_PAGER_PREFIX}:${stateId}:${currentPage - 1}`, + label: "Prev", + disabled: currentPage <= 0 + }, + { + type: ComponentType.Button, + style: ButtonStyle.Secondary, + custom_id: `${PLAYER_SEARCH_PAGER_PREFIX}:${stateId}:${currentPage + 1}`, + label: "Next", + disabled: currentPage >= totalPages - 1 + } + ] + } + ] + } +} + +const formatPlayerSearchSummary = (rawResponse: unknown) => { + const response = playerSearchRoute.responseSchema.parse(rawResponse) + const stateId = putPlayerSearchPagerState(response) + return renderPlayerSearchSummary(response, stateId, 0) +} + +const discordResponseByCommandName: Record = { + instance: { + mapSuccess: response => formatInstanceDiscordSummary(response as z.infer), + mapKnownErrors: { + [ErrorCode.InstanceNotFoundError]: () => buildDiscordContentMessage("Instance not found.") + } + }, + "player-search": { + mapSuccess: response => formatPlayerSearchSummary(response) + } +} + +export const getDiscordResponseMapper = (binding: DiscordExposedRoute): DiscordResponseMapper => { + return discordResponseByCommandName[binding.commandName] ?? {} +} + +export const mapDiscordSuccess = ( + binding: DiscordExposedRoute, + result: DiscordInvocationSuccess +): DiscordComponentsV2Response["data"] | null => { + return getDiscordResponseMapper(binding).mapSuccess?.(result.response) ?? null +} + +export const mapDiscordKnownError = ( + binding: DiscordExposedRoute, + result: DiscordInvocationFailure +): DiscordComponentsV2Response["data"] | null => { + return getDiscordResponseMapper(binding).mapKnownErrors?.[result.code]?.(result.error) ?? null +} + +export const mapDiscordComponentInteraction = ( + interaction: DiscordInteraction +): DiscordComponentsV2Response["data"] | null => { + if (interaction.type !== InteractionType.MessageComponent) return null + const customId = interaction.data?.custom_id ?? null + if (!customId) return null + const parsed = parsePlayerSearchButtonId(customId) + if (!parsed) return null + const state = getPlayerSearchPagerState(parsed.stateId) + if (!state) { + return buildDiscordContentMessage("This player search session expired. Run the command again.") + } + return renderPlayerSearchSummary(state.response, parsed.stateId, parsed.page) +} + diff --git a/src/integrations/discord/types.ts b/src/integrations/discord/types.ts new file mode 100644 index 00000000..da36fdbb --- /dev/null +++ b/src/integrations/discord/types.ts @@ -0,0 +1,45 @@ +import { ApplicationCommandOptionType, InteractionResponseType, InteractionType } from "discord-api-types/v10" +import { IncomingHttpHeaders } from "http" + +export type DiscordInteractionDataOption = { + name: string + type: ApplicationCommandOptionType + value?: string | number | boolean + options?: DiscordInteractionDataOption[] +} + +export type DiscordInteraction = { + id: string + application_id?: string + type: InteractionType + token: string + guild_id?: string + channel_id?: string + member?: { + user?: { + id: string + } + } + data?: { + id?: string + name?: string + options?: DiscordInteractionDataOption[] + custom_id?: string + } +} + +export type DiscordApiStyleRequest = { + params: Record + query: Record + body: unknown + headers: IncomingHttpHeaders +} + +export type DiscordComponentsV2Response = { + type: InteractionResponseType.ChannelMessageWithSource + data: { + flags?: number + content?: string + components?: unknown[] + } +} diff --git a/src/integrations/postgres/reader.ts b/src/integrations/postgres/reader.ts index 46c2ce00..32c46be0 100644 --- a/src/integrations/postgres/reader.ts +++ b/src/integrations/postgres/reader.ts @@ -5,7 +5,7 @@ export const readerMethods = (pool: Pool) => { return { async queryRow(sql: string, options: QueryOptions = {}): Promise { const rows = await executeQuery(pool, sql, "query_row", options) - return (rows[0] as T) || null + return (rows[0]) || null }, async queryRows(sql: string, options: QueryOptions = {}): Promise { diff --git a/src/integrations/postgres/transactional.ts b/src/integrations/postgres/transactional.ts index 704d8e34..46866f05 100644 --- a/src/integrations/postgres/transactional.ts +++ b/src/integrations/postgres/transactional.ts @@ -32,7 +32,7 @@ export function createTransactional(config: { const tx = { async queryRow(sql: string, options: QueryOptions = {}): Promise { const rows = await executeQuery(client, sql, "query_row", options) - return (rows[0] as T) || null + return (rows[0]) || null }, async queryRows(sql: string, options: QueryOptions = {}): Promise { return executeQuery(client, sql, "query_rows", options) diff --git a/src/routes/authorize/admin.test.ts b/src/routes/authorize/admin.test.ts index b1b8d8c8..b48010e0 100644 --- a/src/routes/authorize/admin.test.ts +++ b/src/routes/authorize/admin.test.ts @@ -15,7 +15,7 @@ describe("authorize 200", () => { expectOk(result) if (result.type === "ok") { - jwt.verify(result.parsed.value, process.env.JWT_SECRET!, (err, result) => { + jwt.verify(result.parsed.value, process.env.JWT_SECRET, (err, result) => { expect(err).toBeNull() expect(result).toMatchObject({ isAdmin: true, diff --git a/src/routes/authorize/user.test.ts b/src/routes/authorize/user.test.ts index 251d3968..4770ab27 100644 --- a/src/routes/authorize/user.test.ts +++ b/src/routes/authorize/user.test.ts @@ -16,7 +16,7 @@ describe("authorize 200", () => { expectOk(result) if (result.type === "ok") { - jwt.verify(result.parsed.value, process.env.JWT_SECRET!, (err, result) => { + jwt.verify(result.parsed.value, process.env.JWT_SECRET, (err, result) => { expect(err).toBeNull() expect(result).toMatchObject({ isAdmin: false, diff --git a/src/routes/index.ts b/src/routes/index.ts index a50b958e..d3728b08 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -10,6 +10,7 @@ import { metricsRouter } from "./metrics" import { pgcrRoute } from "./pgcr" import { playerRouter } from "./player" import { statusRoute } from "./status" +import { subscriptionsRouter } from "./subscriptions" export const router = new RaidHubRouter({ routes: [ @@ -56,6 +57,10 @@ export const router = new RaidHubRouter({ { path: "/authorize/user", route: userAuthorizationRoute + }, + { + path: "/subscriptions", + route: subscriptionsRouter } ] }) diff --git a/src/routes/instance.ts b/src/routes/instance.ts index be503d11..de87793c 100644 --- a/src/routes/instance.ts +++ b/src/routes/instance.ts @@ -33,37 +33,33 @@ export const instanceRoute = new RaidHubRoute({ }, async handler(req, after) { const instanceId = req.params.instanceId - const data = await getInstanceExtended(instanceId) - if (!data) { return RaidHubRoute.fail(ErrorCode.InstanceNotFoundError, { - instanceId: instanceId - }) - } else { - after(async () => { - await Promise.allSettled([ - Promise.allSettled( - data.players.flatMap(player => - player.characters - .filter(c => !c.classHash || !c.emblemHash) - .map(c => - instanceCharacterQueue.sendJson({ - instanceId, - membershipId: player.playerInfo.membershipId, - characterId: c.characterId - }) - ) - ) - ), - Promise.allSettled( - data.players - .slice(0, 12) - .map(p => playersQueue.send(p.playerInfo.membershipId)) - ) - ]) + instanceId }) - return RaidHubRoute.ok(data) } + + after(async () => { + await Promise.allSettled([ + Promise.allSettled( + data.players.flatMap(player => + player.characters + .filter(c => !c.classHash || !c.emblemHash) + .map(c => + instanceCharacterQueue.sendJson({ + instanceId, + membershipId: player.playerInfo.membershipId, + characterId: c.characterId + }) + ) + ) + ), + Promise.allSettled( + data.players.slice(0, 12).map(p => playersQueue.send(p.playerInfo.membershipId)) + ) + ]) + }) + return RaidHubRoute.ok(data) } }) diff --git a/src/routes/player/membershipId/history.ts b/src/routes/player/membershipId/history.ts index 2e9461dc..f448b3d7 100644 --- a/src/routes/player/membershipId/history.ts +++ b/src/routes/player/membershipId/history.ts @@ -85,7 +85,7 @@ in order to optimize performance. Subsequent requests will return the full numbe return RaidHubRoute.fail(ErrorCode.PlayerNotFoundError, { membershipId }) } else if ( player.isPrivate && - !(await canAccessProtectedResource(membershipId, req.headers.authorization ?? "")) + !(await canAccessProtectedResource(membershipId, req.auth)) ) { return RaidHubRoute.fail(ErrorCode.PlayerPrivateProfileError, { membershipId }) } diff --git a/src/routes/player/membershipId/instances.ts b/src/routes/player/membershipId/instances.ts index 37ac69a3..22605874 100644 --- a/src/routes/player/membershipId/instances.ts +++ b/src/routes/player/membershipId/instances.ts @@ -69,10 +69,7 @@ export const playerInstancesRoute = new RaidHubRoute({ async handler(req) { const targetMembershipId = req.params.membershipId const player = getPlayer(targetMembershipId) - const canAccess = canAccessProtectedResource( - targetMembershipId, - req.headers.authorization ?? "" - ) + const canAccess = canAccessProtectedResource(targetMembershipId, req.auth) if (!(await player)) { return RaidHubRoute.fail(ErrorCode.PlayerNotFoundError, { diff --git a/src/routes/player/membershipId/profile.ts b/src/routes/player/membershipId/profile.ts index 07a29140..5d587c65 100644 --- a/src/routes/player/membershipId/profile.ts +++ b/src/routes/player/membershipId/profile.ts @@ -65,7 +65,7 @@ This is used to hydrate the RaidHub profile page`, return RaidHubRoute.fail(ErrorCode.PlayerNotFoundError, { membershipId }) } else if ( player.isPrivate && - !(await canAccessProtectedResource(membershipId, req.headers.authorization ?? "")) + !(await canAccessProtectedResource(membershipId, req.auth)) ) { return RaidHubRoute.fail(ErrorCode.PlayerPrivateProfileError, { membershipId }) } diff --git a/src/routes/player/membershipId/teammates.ts b/src/routes/player/membershipId/teammates.ts index 231b4411..c6a78238 100644 --- a/src/routes/player/membershipId/teammates.ts +++ b/src/routes/player/membershipId/teammates.ts @@ -48,7 +48,7 @@ export const playerTeammatesRoute = new RaidHubRoute({ return RaidHubRoute.fail(ErrorCode.PlayerNotFoundError, { membershipId }) } else if ( player.isPrivate && - !(await canAccessProtectedResource(membershipId, req.headers.authorization ?? "")) + !(await canAccessProtectedResource(membershipId, req.auth)) ) { return RaidHubRoute.fail(ErrorCode.PlayerPrivateProfileError, { membershipId }) } diff --git a/src/routes/player/search.ts b/src/routes/player/search.ts index 73814ec1..e576db46 100644 --- a/src/routes/player/search.ts +++ b/src/routes/player/search.ts @@ -13,6 +13,9 @@ Players who have not attempted a raid may not appear in the search results. Results are ordered by a combination of the number of raid completions and last played date.`, query: z.object({ count: z.coerce.number().int().min(1).max(50).default(20), + offset: z.coerce.number().int().min(0).max(5000).default(0).openapi({ + description: "Number of leading search hits to skip (for pagination). Must be 0 when count is the full result window." + }), query: z.string().min(1).max(40), membershipType: zDestinyMembershipType.default(-1).openapi({ description: @@ -30,6 +33,7 @@ Results are ordered by a combination of the number of raid completions and last .object({ params: z.object({ count: zNaturalNumber(), + offset: zNaturalNumber(), query: z.string() }), results: z.array(zPlayerInfo) @@ -39,15 +43,16 @@ Results are ordered by a combination of the number of raid completions and last }, middleware: [cacheControl(120)], async handler(req) { - const { query, count, membershipType, global } = req.query + const { query, count, offset, membershipType, global } = req.query const { searchTerm, results } = await searchForPlayer(query, { count, + offset, membershipType: membershipType === -1 ? undefined : membershipType, global }) return RaidHubRoute.ok({ - params: { count, query: searchTerm }, + params: { count, offset, query: searchTerm }, results }) } diff --git a/src/routes/subscriptions/discord/index.ts b/src/routes/subscriptions/discord/index.ts new file mode 100644 index 00000000..da7b7a78 --- /dev/null +++ b/src/routes/subscriptions/discord/index.ts @@ -0,0 +1,23 @@ +import { RaidHubRouter } from "@/core/RaidHubRouter" +import { + deleteDiscordWebhookRoute, + getDiscordWebhookStatusRoute, + putDiscordWebhookRoute +} from "./webhooks" + +export const subscriptionsDiscordRouter = new RaidHubRouter({ + routes: [ + { + path: "/webhooks", + route: getDiscordWebhookStatusRoute + }, + { + path: "/webhooks", + route: putDiscordWebhookRoute + }, + { + path: "/webhooks", + route: deleteDiscordWebhookRoute + } + ] +}) diff --git a/src/routes/subscriptions/discord/webhooks.ts b/src/routes/subscriptions/discord/webhooks.ts new file mode 100644 index 00000000..268a5fcf --- /dev/null +++ b/src/routes/subscriptions/discord/webhooks.ts @@ -0,0 +1,98 @@ +import { RaidHubRoute } from "@/core/RaidHubRoute" +import { ErrorCode } from "@/schema/errors/ErrorCode" +import { + zDiscordWebhookDeleteResponse, + zDiscordWebhookBody, + zDiscordWebhookPutResponse, + zDiscordWebhookStatusResponse +} from "@/schema/components/DiscordSubscriptionWebhook" +import { + deleteDiscordWebhook, + getDiscordWebhookStatus, + upsertDiscordWebhook +} from "@/services/subscriptions/discord-webhooks" +import { z } from "zod" + +const discordGuildChannelAuthErrors = [ + { + statusCode: 403 as const, + code: ErrorCode.InsufficientPermissionsError, + schema: z.object({ + message: z.literal("Forbidden") + }) + } +] + +export const putDiscordWebhookRoute = new RaidHubRoute({ + method: "put", + description: + "Create or update the RaidHub subscription webhook for this channel (idempotent upsert).", + body: zDiscordWebhookBody, + response: { + success: { + statusCode: 200, + schema: zDiscordWebhookPutResponse + }, + errors: discordGuildChannelAuthErrors + }, + async handler(req) { + const guildId = req.discord?.guildId + const channelId = req.discord?.channelId + if (!guildId || !channelId) { + return RaidHubRoute.fail(ErrorCode.InsufficientPermissionsError, { + message: "Forbidden" as const + }) + } + return RaidHubRoute.ok( + await upsertDiscordWebhook({ + ...req.body, + guildId, + channelId + }) + ) + } +}) + +export const deleteDiscordWebhookRoute = new RaidHubRoute({ + method: "delete", + description: "Delete a Discord subscription webhook registration for the current channel.", + response: { + success: { + statusCode: 200, + schema: zDiscordWebhookDeleteResponse + }, + errors: discordGuildChannelAuthErrors + }, + async handler(req) { + if (!req.discord?.guildId || !req.discord.channelId) { + return RaidHubRoute.fail(ErrorCode.InsufficientPermissionsError, { + message: "Forbidden" as const + }) + } + await deleteDiscordWebhook(req.discord.channelId) + return RaidHubRoute.ok({ + deleted: true + }) + } +}) + +export const getDiscordWebhookStatusRoute = new RaidHubRoute({ + method: "get", + description: "Get RaidHub subscription webhook status for the current channel (no secrets).", + response: { + success: { + statusCode: 200, + schema: zDiscordWebhookStatusResponse + }, + errors: discordGuildChannelAuthErrors + }, + async handler(req) { + if (!req.discord?.guildId || !req.discord.channelId) { + return RaidHubRoute.fail(ErrorCode.InsufficientPermissionsError, { + message: "Forbidden" as const + }) + } + return RaidHubRoute.ok(await getDiscordWebhookStatus(req.discord.channelId)) + } +}) + diff --git a/src/routes/subscriptions/index.ts b/src/routes/subscriptions/index.ts new file mode 100644 index 00000000..2d8ecf33 --- /dev/null +++ b/src/routes/subscriptions/index.ts @@ -0,0 +1,11 @@ +import { RaidHubRouter } from "@/core/RaidHubRouter" +import { subscriptionsDiscordRouter } from "./discord" + +export const subscriptionsRouter = new RaidHubRouter({ + routes: [ + { + path: "/discord", + route: subscriptionsDiscordRouter + } + ] +}) diff --git a/src/schema/components/DiscordSubscriptionWebhook.ts b/src/schema/components/DiscordSubscriptionWebhook.ts new file mode 100644 index 00000000..91cedb3d --- /dev/null +++ b/src/schema/components/DiscordSubscriptionWebhook.ts @@ -0,0 +1,94 @@ +import { registry } from "@/schema/registry" +import { zWholeNumber } from "@/schema/output" +import { z } from "zod" + +export type DiscordWebhookBody = z.input +export const zDiscordWebhookBody = registry.register( + "DiscordWebhookBody", + z + .object({ + name: z.string().min(1).max(80).optional(), + filters: z + .object({ + requireFresh: z.boolean().optional(), + requireCompleted: z.boolean().optional() + }) + .optional(), + targets: z + .object({ + playerMembershipIds: z.array(z.string().regex(/^\d+$/)).optional(), + clanGroupIds: z.array(z.string().regex(/^\d+$/)).optional() + }) + .optional() + }) + .default({}) +) + +const zDiscordWebhookRulesUpsertSummary = z.object({ + players: z.object({ + inserted: z.number().int().nonnegative(), + updated: z.number().int().nonnegative() + }), + clans: z.object({ + inserted: z.number().int().nonnegative(), + updated: z.number().int().nonnegative() + }) +}) + +const zDiscordPlayerRule = z.object({ + membershipId: z.string().regex(/^\d+$/), + requireFresh: z.boolean(), + requireCompleted: z.boolean() +}) + +const zDiscordClanRule = z.object({ + groupId: z.string().regex(/^\d+$/), + requireFresh: z.boolean(), + requireCompleted: z.boolean() +}) + +export type DiscordWebhookPutResponse = z.input +export const zDiscordWebhookPutResponse = registry.register( + "DiscordWebhookPutResponse", + z.object({ + guildId: z.string(), + channelId: z.string(), + webhookId: z.string(), + webhookUrl: z.string().url().optional(), + created: z.boolean(), + activated: z.boolean(), + updated: z.boolean(), + rules: zDiscordWebhookRulesUpsertSummary + }) +) + +export type DiscordWebhookDeleteResponse = z.input +export const zDiscordWebhookDeleteResponse = registry.register( + "DiscordWebhookDeleteResponse", + z.object({ + deleted: z.boolean() + }) +) + +export type DiscordWebhookStatusResponse = z.input +export const zDiscordWebhookStatusResponse = registry.register( + "DiscordWebhookStatusResponse", + z.discriminatedUnion("registered", [ + z.object({ + registered: z.literal(false) + }), + z.object({ + registered: z.literal(true), + guildId: z.string(), + channelId: z.string(), + webhookId: z.string(), + destinationActive: z.boolean(), + consecutiveDeliveryFailures: zWholeNumber(), + lastDeliverySuccessAt: z.string().nullable(), + lastDeliveryFailureAt: z.string().nullable(), + lastDeliveryError: z.string().nullable(), + players: z.array(zDiscordPlayerRule), + clans: z.array(zDiscordClanRule) + }) + ]) +) diff --git a/src/schema/errors/ErrorCode.ts b/src/schema/errors/ErrorCode.ts index 072cdd08..41801d3e 100644 --- a/src/schema/errors/ErrorCode.ts +++ b/src/schema/errors/ErrorCode.ts @@ -24,6 +24,7 @@ export enum ErrorCode { /** Auth */ InsufficientPermissionsError = "InsufficientPermissionsError", InvalidClientSecretError = "InvalidClientSecretError", + InvalidDiscordAuthError = "InvalidDiscordAuthError", /** RaidHub error */ InternalServerError = "InternalServerError", ServiceUnavailableError = "ServiceUnavailableError", diff --git a/src/services/manifest/urls.ts b/src/services/manifest/urls.ts index 2a5cbd7e..0453fda1 100644 --- a/src/services/manifest/urls.ts +++ b/src/services/manifest/urls.ts @@ -16,7 +16,7 @@ export const generateSplashUrls = async (defs: ActivityDefinition[]) => { const processed = processContentUrl(item) if (allValidSlugs.has(processed.slug)) { const activityId = allValidSlugs.get(processed.slug)! - const bucket = result[activityId]! + const bucket = result[activityId] bucket.push(processed) } } diff --git a/src/services/search/player-search.test.ts b/src/services/search/player-search.test.ts index 8c6aaafd..1c22c44a 100644 --- a/src/services/search/player-search.test.ts +++ b/src/services/search/player-search.test.ts @@ -7,6 +7,7 @@ describe("searchForPlayer", () => { test("returns the correct shape", async () => { const data = await searchForPlayer("Newo", { count: 10, + offset: 0, global: true }).catch(console.error) @@ -29,6 +30,7 @@ describe("searchForPlayer", () => { test("returns the correct shape with platform", async () => { const data = await searchForPlayer(" Newo", { count: 10, + offset: 0, global: false, membershipType: 2 }).catch(console.error) diff --git a/src/services/search/player-search.ts b/src/services/search/player-search.ts index 20f75294..83f0ddfe 100644 --- a/src/services/search/player-search.ts +++ b/src/services/search/player-search.ts @@ -12,6 +12,7 @@ export async function searchForPlayer( query: string, opts: { count: number + offset: number membershipType?: Exclude global: boolean } @@ -41,18 +42,20 @@ export async function searchForPlayer( cheat_level AS "cheatLevel" FROM player WHERE lower(${opts.global ? "bungie_name" : "display_name"}) LIKE $1 - ${opts.membershipType ? "AND membership_type = $3" : ""} + ${opts.membershipType ? "AND membership_type = $4" : ""} AND last_seen > TIMESTAMP 'epoch' ORDER BY _search_score DESC - LIMIT $2;`, + LIMIT $2 OFFSET $3;`, { params: opts.membershipType - ? [searchTerm + "%", opts.count, opts.membershipType] - : [searchTerm + "%", opts.count] + ? [searchTerm + "%", opts.count, opts.offset, opts.membershipType] + : [searchTerm + "%", opts.count, opts.offset] } ) ), - isMembershipIdQuery ? getPlayer(trimmedQuery).catch(() => null) : Promise.resolve(null) + isMembershipIdQuery && opts.offset === 0 + ? getPlayer(trimmedQuery).catch(() => null) + : Promise.resolve(null) ]) let results = nameResults diff --git a/src/services/subscriptions/discord-webhooks.test.ts b/src/services/subscriptions/discord-webhooks.test.ts new file mode 100644 index 00000000..dd24f751 --- /dev/null +++ b/src/services/subscriptions/discord-webhooks.test.ts @@ -0,0 +1,195 @@ +import { afterAll, beforeEach, describe, expect, test } from "bun:test" + +import { pgAdmin } from "@/integrations/postgres" +import { getDiscordWebhookStatus, upsertDiscordWebhook } from "./discord-webhooks" + +describe("discord webhook subscriptions service", () => { + const originalQueryRow = pgAdmin.queryRow.bind(pgAdmin) + const originalQueryRows = pgAdmin.queryRows.bind(pgAdmin) + const originalTransaction = pgAdmin.transaction.bind(pgAdmin) + + const queueQueryRow = (values: unknown[]) => { + const queue = [...values] + pgAdmin.queryRow = (async () => { + await Promise.resolve() + if (queue.length === 0) throw new Error("Unexpected queryRow call") + return queue.shift() as never + }) as typeof pgAdmin.queryRow + } + + const queueQueryRows = (values: unknown[]) => { + const queue = [...values] + pgAdmin.queryRows = (async () => { + await Promise.resolve() + if (queue.length === 0) throw new Error("Unexpected queryRows call") + return queue.shift() as never + }) as typeof pgAdmin.queryRows + } + + const queueTransaction = (rows: unknown[], rowsMany: unknown[]) => { + const rowQueue = [...rows] + const rowsQueue = [...rowsMany] + pgAdmin.transaction = (async callback => { + await Promise.resolve() + const tx = { + queryRow: async () => { + await Promise.resolve() + if (rowQueue.length === 0) throw new Error("Unexpected tx.queryRow call") + return rowQueue.shift() as never + }, + queryRows: async () => { + await Promise.resolve() + if (rowsQueue.length === 0) throw new Error("Unexpected tx.queryRows call") + return rowsQueue.shift() as never + } + } + return callback(tx as never) + }) as typeof pgAdmin.transaction + } + + beforeEach(() => { + pgAdmin.queryRow = originalQueryRow + pgAdmin.queryRows = originalQueryRows + pgAdmin.transaction = originalTransaction + }) + + afterAll(() => { + pgAdmin.queryRow = originalQueryRow + pgAdmin.queryRows = originalQueryRows + pgAdmin.transaction = originalTransaction + }) + + test("upsertDiscordWebhook updates existing active destination", async () => { + queueQueryRow([ + { + destinationId: "99", + webhookId: "webhook_abc", + isActive: true + }, + { + destinationId: "99" + }, + { + id: "99" + } + ]) + queueQueryRows([[]]) + queueTransaction( + [{ destinationId: "99" }, { id: "99" }], + [[]] + ) + + const result = await upsertDiscordWebhook({ + guildId: "guild_1", + channelId: "123456789", + filters: {}, + targets: {} + }) + + expect(result).toEqual({ + guildId: "guild_1", + channelId: "123456789", + webhookId: "webhook_abc", + created: false, + activated: false, + updated: true, + rules: { + players: { inserted: 0, updated: 0 }, + clans: { inserted: 0, updated: 0 } + } + }) + }) + + test("upsertDiscordWebhook reactivates existing inactive destination", async () => { + queueQueryRow([ + { + destinationId: "77", + webhookId: "webhook_xyz", + isActive: false + }, + { + destinationId: "77" + }, + { + id: "77" + } + ]) + queueQueryRows([[], []]) + queueTransaction( + [{ destinationId: "77" }, { id: "77" }], + [[]] + ) + + const result = await upsertDiscordWebhook({ + guildId: "guild_2", + channelId: "channel_2", + filters: {}, + targets: {} + }) + + expect(result.activated).toBe(true) + expect(result.updated).toBe(true) + expect(result.created).toBe(false) + expect(result.webhookId).toBe("webhook_xyz") + }) + + test("getDiscordWebhookStatus returns full player/clan rule DTOs", async () => { + queueQueryRow([ + { + destinationId: "42", + destinationActive: true, + consecutiveDeliveryFailures: 3, + lastDeliverySuccessAt: new Date("2026-04-22T00:00:00.000Z"), + lastDeliveryFailureAt: null, + lastDeliveryError: "timeout", + guildId: "guild_9", + channelId: "channel_9", + webhookId: "webhook_9" + } + ]) + queueQueryRows([ + [ + { + membershipId: "4611686018467831285", + requireFresh: true, + requireCompleted: false + } + ], + [ + { + groupId: "123456", + requireFresh: false, + requireCompleted: true + } + ] + ]) + + const result = await getDiscordWebhookStatus("channel_9") + + expect(result).toEqual({ + registered: true, + guildId: "guild_9", + channelId: "channel_9", + webhookId: "webhook_9", + destinationActive: true, + consecutiveDeliveryFailures: 3, + lastDeliverySuccessAt: "2026-04-22T00:00:00.000Z", + lastDeliveryFailureAt: null, + lastDeliveryError: "timeout", + players: [ + { + membershipId: "4611686018467831285", + requireFresh: true, + requireCompleted: false + } + ], + clans: [ + { + groupId: "123456", + requireFresh: false, + requireCompleted: true + } + ] + }) + }) +}) diff --git a/src/services/subscriptions/discord-webhooks.ts b/src/services/subscriptions/discord-webhooks.ts new file mode 100644 index 00000000..5ef505df --- /dev/null +++ b/src/services/subscriptions/discord-webhooks.ts @@ -0,0 +1,617 @@ +import { pgAdmin } from "@/integrations/postgres" +import { Logger } from "@/lib/utils/logging" + +const logger = new Logger("DISCORD_SUBSCRIPTIONS_SERVICE") + +export type RegisterDiscordWebhookInput = { + guildId: string + channelId: string + name?: string + filters?: { + requireFresh?: boolean + requireCompleted?: boolean + } + targets?: { + playerMembershipIds?: string[] + clanGroupIds?: string[] + } +} + +export type RegisterDiscordWebhookResult = { + guildId: string + channelId: string + webhookId: string + webhookUrl: string + created: boolean + activated: boolean + rules: { + players: { + inserted: number + updated: number + } + clans: { + inserted: number + updated: number + } + } +} + +export type UpdateDiscordWebhookInput = { + guildId: string + filters?: { + requireFresh?: boolean + requireCompleted?: boolean + } + targets?: { + playerMembershipIds?: string[] + clanGroupIds?: string[] + } +} + +export type UpdateDiscordWebhookResult = { + guildId: string + channelId: string + updated: boolean + rules: { + players: { + inserted: number + updated: number + } + clans: { + inserted: number + updated: number + } + } +} + +export type UpsertDiscordWebhookInput = RegisterDiscordWebhookInput + +export type UpsertDiscordWebhookResult = { + guildId: string + channelId: string + webhookId: string + webhookUrl?: string + created: boolean + activated: boolean + updated: boolean + rules: RegisterDiscordWebhookResult["rules"] +} + +const createDiscordWebhook = async ( + body: Pick +) => { + const token = process.env.DISCORD_BOT_TOKEN + if (!token) { + throw new Error("DISCORD_BOT_TOKEN is not configured") + } + + // Keep webhook identity aligned with RaidHub-Services defaults. + const defaultWebhookName = "RaidHub" + const requestedName = body.name?.trim() + const webhookName = + requestedName && requestedName.length > 0 + ? requestedName.slice(0, 80) + : defaultWebhookName + + const response = await fetch( + `https://discord.com/api/v10/channels/${body.channelId}/webhooks`, + { + method: "POST", + headers: { + Authorization: `Bot ${token}`, + "Content-Type": "application/json" + }, + body: JSON.stringify({ + name: webhookName + }) + } + ) + + if (!response.ok) { + const detail = await response.text() + throw new Error(`Discord webhook create failed with status ${response.status}: ${detail}`) + } + + const data = (await response.json()) as { id: string; token: string } + return { + id: data.id, + token: data.token, + url: `https://discord.com/api/webhooks/${data.id}/${data.token}` + } +} + +const validateDiscordWebhookUrl = (raw: string) => { + const value = raw.trim() + if (!value) throw new Error("webhookUrl is empty") + const isDiscord = + value.startsWith("https://discord.com/api/webhooks/") || + value.startsWith("https://discordapp.com/api/webhooks/") + if (!isDiscord) { + throw new Error("webhookUrl must be a Discord Incoming Webhook URL") + } + return value +} + +const toBigIntString = (value: string) => BigInt(value).toString() + +async function getDiscordDestinationIdByChannelId( + db: Pick, + channelId: string +): Promise { + const row = await db.queryRow<{ destinationId: string }>( + `SELECT destination_id::text AS "destinationId" + FROM subscriptions.discord_destination_config + WHERE channel_id = $1 + LIMIT 1`, + { params: [channelId] } + ) + if (!row) { + throw new Error(`Discord channel ${channelId} not found`) + } + return row.destinationId +} + +async function upsertDiscordRules( + db: Pick, + destinationId: string, + options: { + requireFresh: boolean + requireCompleted: boolean + playerMembershipIds: string[] + clanGroupIds: string[] + } +) { + const { requireFresh, requireCompleted, playerMembershipIds, clanGroupIds } = options + const playerInsertResults = await Promise.all( + playerMembershipIds.map(async membershipId => { + const insertedRows = await db.queryRows<{ rowCount: number }>( + `INSERT INTO subscriptions.rule (destination_id, scope, membership_id, require_fresh, require_completed) + SELECT $1::bigint, 'player', $2::bigint, $3, $4 + WHERE NOT EXISTS ( + SELECT 1 FROM subscriptions.rule r + WHERE r.destination_id = $1::bigint + AND r.scope = 'player' + AND r.membership_id = $2::bigint + AND r.is_active + ) + RETURNING 1 AS "rowCount"`, + { + params: [destinationId, membershipId, requireFresh, requireCompleted] + } + ) + + if (insertedRows.length > 0) return { inserted: 1, updated: 0 } + + await db.queryRows( + `UPDATE subscriptions.rule + SET require_fresh = $3, + require_completed = $4 + WHERE destination_id = $1::bigint + AND scope = 'player' + AND membership_id = $2::bigint + AND is_active`, + { + params: [destinationId, membershipId, requireFresh, requireCompleted] + } + ) + return { inserted: 0, updated: 1 } + }) + ) + + const clanInsertResults = await Promise.all( + clanGroupIds.map(async groupId => { + const insertedRows = await db.queryRows<{ rowCount: number }>( + `INSERT INTO subscriptions.rule (destination_id, scope, group_id, require_fresh, require_completed) + SELECT $1::bigint, 'clan', $2::bigint, $3, $4 + WHERE NOT EXISTS ( + SELECT 1 FROM subscriptions.rule r + WHERE r.destination_id = $1::bigint + AND r.scope = 'clan' + AND r.group_id = $2::bigint + AND r.is_active + ) + RETURNING 1 AS "rowCount"`, + { + params: [destinationId, groupId, requireFresh, requireCompleted] + } + ) + + if (insertedRows.length > 0) return { inserted: 1, updated: 0 } + + await db.queryRows( + `UPDATE subscriptions.rule + SET require_fresh = $3, + require_completed = $4 + WHERE destination_id = $1::bigint + AND scope = 'clan' + AND group_id = $2::bigint + AND is_active`, + { + params: [destinationId, groupId, requireFresh, requireCompleted] + } + ) + return { inserted: 0, updated: 1 } + }) + ) + + return { + players: { + inserted: playerInsertResults.filter(r => r.inserted === 1).length, + updated: playerInsertResults.filter(r => r.updated === 1).length + }, + clans: { + inserted: clanInsertResults.filter(r => r.inserted === 1).length, + updated: clanInsertResults.filter(r => r.updated === 1).length + } + } +} + +export async function registerDiscordWebhook( + input: RegisterDiscordWebhookInput +): Promise { + logger.info("DISCORD_WEBHOOK_REGISTER_REQUESTED", { + guildId: input.guildId, + channelId: input.channelId, + hasName: Boolean(input.name), + playerTargets: input.targets?.playerMembershipIds?.length ?? 0, + clanTargets: input.targets?.clanGroupIds?.length ?? 0 + }) + const webhook = await createDiscordWebhook({ + channelId: input.channelId, + name: input.name + }) + const webhookUrl = validateDiscordWebhookUrl(webhook.url) + const requireFresh = input.filters?.requireFresh ?? false + const requireCompleted = input.filters?.requireCompleted ?? false + const playerMembershipIds = (input.targets?.playerMembershipIds ?? []).map(toBigIntString) + const clanGroupIds = (input.targets?.clanGroupIds ?? []).map(toBigIntString) + + const { created, activated, rules } = await pgAdmin.transaction(async tx => { + const existing = await tx.queryRow<{ id: string; isActive: boolean }>( + `SELECT d.id::text AS "id", d.is_active AS "isActive" + FROM subscriptions.discord_destination_config c + INNER JOIN subscriptions.destination d ON d.id = c.destination_id + WHERE c.channel_id = $1 + LIMIT 1`, + { params: [input.channelId] } + ) + + let destinationId: string + let created = false + let activated = false + if (existing) { + destinationId = existing.id + if (!existing.isActive) { + await tx.queryRows( + `UPDATE subscriptions.destination + SET is_active = true, updated_at = NOW() + WHERE id = $1::bigint`, + { params: [existing.id] } + ) + activated = true + } + } else { + const inserted = await tx.queryRow<{ id: string }>( + `INSERT INTO subscriptions.destination (channel_type) + VALUES ($1) + RETURNING id::text AS "id"`, + { params: ["discord_webhook"] } + ) + if (!inserted) throw new Error("Failed to create subscription destination") + destinationId = inserted.id + created = true + } + + await tx.queryRows( + `INSERT INTO subscriptions.discord_destination_config + (destination_id, guild_id, channel_id, webhook_id, webhook_token, updated_at) + VALUES ($1::bigint, $2, $3, $4, $5, NOW()) + ON CONFLICT (destination_id) + DO UPDATE SET + guild_id = EXCLUDED.guild_id, + channel_id = EXCLUDED.channel_id, + webhook_id = EXCLUDED.webhook_id, + webhook_token = EXCLUDED.webhook_token, + updated_at = NOW()`, + { + params: [destinationId, input.guildId, input.channelId, webhook.id, webhook.token] + } + ) + + const rules = await upsertDiscordRules(tx, destinationId, { + requireFresh, + requireCompleted, + playerMembershipIds, + clanGroupIds + }) + + return { created, activated, rules } + }) + + logger.info("DISCORD_WEBHOOK_REGISTER_COMPLETED", { + guildId: input.guildId, + channelId: input.channelId, + webhookId: webhook.id, + created, + activated, + playerRulesInserted: rules.players.inserted, + playerRulesUpdated: rules.players.updated, + clanRulesInserted: rules.clans.inserted, + clanRulesUpdated: rules.clans.updated + }) + + return { + guildId: input.guildId, + channelId: input.channelId, + webhookId: webhook.id, + webhookUrl, + created, + activated, + rules + } +} + +export async function updateDiscordWebhook( + channelId: string, + input: UpdateDiscordWebhookInput +): Promise { + logger.info("DISCORD_WEBHOOK_UPDATE_REQUESTED", { + guildId: input.guildId, + channelId, + playerTargets: input.targets?.playerMembershipIds?.length ?? 0, + clanTargets: input.targets?.clanGroupIds?.length ?? 0, + requireFresh: input.filters?.requireFresh ?? false, + requireCompleted: input.filters?.requireCompleted ?? false + }) + const requireFresh = input.filters?.requireFresh ?? false + const requireCompleted = input.filters?.requireCompleted ?? false + const playerMembershipIds = (input.targets?.playerMembershipIds ?? []).map(toBigIntString) + const clanGroupIds = (input.targets?.clanGroupIds ?? []).map(toBigIntString) + + const rules = await pgAdmin.transaction(async tx => { + const destinationId = await getDiscordDestinationIdByChannelId(tx, channelId) + const existing = await tx.queryRow<{ id: string }>( + `SELECT id::text AS "id" + FROM subscriptions.destination + WHERE id = $1::bigint + LIMIT 1`, + { params: [destinationId] } + ) + if (!existing) { + throw new Error(`Subscription destination ${destinationId} not found`) + } + + await tx.queryRows( + `UPDATE subscriptions.discord_destination_config + SET guild_id = $2, + updated_at = NOW() + WHERE destination_id = $1::bigint`, + { params: [destinationId, input.guildId] } + ) + + return upsertDiscordRules(tx, destinationId, { + requireFresh, + requireCompleted, + playerMembershipIds, + clanGroupIds + }) + }) + + logger.info("DISCORD_WEBHOOK_UPDATE_COMPLETED", { + guildId: input.guildId, + channelId, + playerRulesInserted: rules.players.inserted, + playerRulesUpdated: rules.players.updated, + clanRulesInserted: rules.clans.inserted, + clanRulesUpdated: rules.clans.updated + }) + + return { + guildId: input.guildId, + channelId, + updated: true, + rules + } +} + +export async function upsertDiscordWebhook( + input: UpsertDiscordWebhookInput +): Promise { + logger.info("DISCORD_WEBHOOK_UPSERT_REQUESTED", { + guildId: input.guildId, + channelId: input.channelId + }) + const existing = await pgAdmin.queryRow<{ + destinationId: string + webhookId: string + isActive: boolean + }>( + `SELECT c.destination_id::text AS "destinationId", c.webhook_id AS "webhookId", d.is_active AS "isActive" + FROM subscriptions.discord_destination_config c + INNER JOIN subscriptions.destination d ON d.id = c.destination_id + WHERE c.channel_id = $1 + LIMIT 1`, + { params: [input.channelId] } + ) + + if (!existing) { + const reg = await registerDiscordWebhook(input) + logger.info("DISCORD_WEBHOOK_UPSERT_REGISTERED", { + guildId: reg.guildId, + channelId: reg.channelId, + webhookId: reg.webhookId + }) + return { + guildId: reg.guildId, + channelId: reg.channelId, + webhookId: reg.webhookId, + webhookUrl: reg.webhookUrl, + created: reg.created, + activated: reg.activated, + updated: false, + rules: reg.rules + } + } + + let activated = false + if (!existing.isActive) { + await pgAdmin.queryRows( + `UPDATE subscriptions.destination + SET is_active = true, + updated_at = NOW(), + deactivated_at = NULL, + deactivation_reason = NULL + WHERE id = $1::bigint`, + { params: [existing.destinationId] } + ) + activated = true + logger.info("DISCORD_WEBHOOK_REACTIVATED", { + destinationId: existing.destinationId, + channelId: input.channelId + }) + } + + const upd = await updateDiscordWebhook(input.channelId, { + guildId: input.guildId, + filters: input.filters, + targets: input.targets + }) + + return { + guildId: upd.guildId, + channelId: upd.channelId, + webhookId: existing.webhookId, + created: false, + activated, + updated: true, + rules: upd.rules + } +} + +export async function deleteDiscordWebhook(channelId: string): Promise { + logger.info("DISCORD_WEBHOOK_DELETE_REQUESTED", { channelId }) + await pgAdmin.transaction(async tx => { + const destinationId = await getDiscordDestinationIdByChannelId(tx, channelId) + await tx.queryRows( + `UPDATE subscriptions.destination + SET is_active = false, updated_at = NOW(), deactivated_at = NOW(), deactivation_reason = 'api_deactivate' + WHERE id = $1::bigint`, + { params: [destinationId] } + ) + logger.info("DISCORD_WEBHOOK_DEACTIVATED", { + channelId, + destinationId + }) + }) +} + +const toIsoString = (value: unknown): string | null => { + if (value == null) return null + if (value instanceof Date) return value.toISOString() + if (typeof value === "string") return value + return String(value) +} + +export type DiscordWebhookStatusResult = + | { registered: false } + | { + registered: true + guildId: string + channelId: string + webhookId: string + destinationActive: boolean + consecutiveDeliveryFailures: number + lastDeliverySuccessAt: string | null + lastDeliveryFailureAt: string | null + lastDeliveryError: string | null + players: { + membershipId: string + requireFresh: boolean + requireCompleted: boolean + }[] + clans: { + groupId: string + requireFresh: boolean + requireCompleted: boolean + }[] + } + +export async function getDiscordWebhookStatus(channelId: string): Promise { + logger.debug("DISCORD_WEBHOOK_STATUS_REQUESTED", { channelId }) + const row = await pgAdmin.queryRow<{ + destinationId: string + destinationActive: boolean + consecutiveDeliveryFailures: number + lastDeliverySuccessAt: Date | null + lastDeliveryFailureAt: Date | null + lastDeliveryError: string | null + guildId: string + channelId: string + webhookId: string + }>( + `SELECT + d.id::text AS "destinationId", + d.is_active AS "destinationActive", + d.consecutive_delivery_failures AS "consecutiveDeliveryFailures", + d.last_delivery_success_at AS "lastDeliverySuccessAt", + d.last_delivery_failure_at AS "lastDeliveryFailureAt", + d.last_delivery_error AS "lastDeliveryError", + c.guild_id AS "guildId", + c.channel_id AS "channelId", + c.webhook_id AS "webhookId" + FROM subscriptions.discord_destination_config c + INNER JOIN subscriptions.destination d ON d.id = c.destination_id + WHERE c.channel_id = $1 + LIMIT 1`, + { params: [channelId] } + ) + + if (!row) { + logger.info("DISCORD_WEBHOOK_STATUS_NOT_REGISTERED", { channelId }) + return { registered: false } + } + + const [playerRows, clanRows] = await Promise.all([ + pgAdmin.queryRows<{ membershipId: string; requireFresh: boolean; requireCompleted: boolean }>( + `SELECT + membership_id::text AS "membershipId", + require_fresh AS "requireFresh", + require_completed AS "requireCompleted" + FROM subscriptions.rule + WHERE destination_id = $1::bigint AND scope = 'player' AND is_active + ORDER BY membership_id`, + { params: [row.destinationId] } + ), + pgAdmin.queryRows<{ groupId: string; requireFresh: boolean; requireCompleted: boolean }>( + `SELECT + group_id::text AS "groupId", + require_fresh AS "requireFresh", + require_completed AS "requireCompleted" + FROM subscriptions.rule + WHERE destination_id = $1::bigint AND scope = 'clan' AND is_active + ORDER BY group_id`, + { params: [row.destinationId] } + ) + ]) + + const status = { + registered: true, + guildId: row.guildId, + channelId: row.channelId, + webhookId: row.webhookId, + destinationActive: row.destinationActive, + consecutiveDeliveryFailures: row.consecutiveDeliveryFailures, + lastDeliverySuccessAt: toIsoString(row.lastDeliverySuccessAt), + lastDeliveryFailureAt: toIsoString(row.lastDeliveryFailureAt), + lastDeliveryError: row.lastDeliveryError, + players: playerRows, + clans: clanRows + } + logger.info("DISCORD_WEBHOOK_STATUS_FETCHED", { + channelId, + destinationActive: status.destinationActive, + playerRules: status.players.length, + clanRules: status.clans.length + }) + return status +} diff --git a/tsconfig.json b/tsconfig.json index 8018138d..09a1c5a1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -33,6 +33,7 @@ "include": [ "src/**/*.ts", "src/**/*.test.ts", + "scripts/**/*.ts", "open-api/generate.ts", "api-keys.json" ] From 12e7c9c6d79c8893aa69ba2270f329dde387711a Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 09:21:25 -0400 Subject: [PATCH 02/22] fix typechecl --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b7b7ce81..a6eec9c7 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "scripts": { "prepare": "husky", "dev": "bun --watch ./src/index.ts", - "typecheck": "eslint . --ext .ts", + "typecheck": "bunx tsc --noEmit", "lint": "eslint . --ext .ts", "format": "prettier '**/*.{ts,json}'", "docs": "bun run ./open-api/generate.ts", From 0ddeac19759943747f77ae8161ed878e8fc304cf Mon Sep 17 00:00:00 2001 From: Owen <98496129+owens1127@users.noreply.github.com> Date: Wed, 22 Apr 2026 09:39:21 -0400 Subject: [PATCH 03/22] Delete package-lock.json --- package-lock.json | 9296 --------------------------------------------- 1 file changed, 9296 deletions(-) delete mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index ffd0163d..00000000 --- a/package-lock.json +++ /dev/null @@ -1,9296 +0,0 @@ -{ - "name": "raidhub-api", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "raidhub-api", - "version": "1.0.0", - "license": "UNLICENSED", - "dependencies": { - "@aws-sdk/client-s3": "^3.908.0", - "@clickhouse/client": "^1.5.0", - "@sentry/bun": "^10.23.0", - "@types/pg": "^8.15.6", - "amqplib": "^0.10.3", - "bungie-net-core": "2.1.3", - "compression": "^1.7.4", - "discord-api-types": "^0.38.47", - "express": "^4.18.2", - "jsonwebtoken": "^9.0.2", - "pg": "^8.16.3", - "prom-client": "^15.1.1", - "zod": "^3.22.4" - }, - "devDependencies": { - "@asteasolutions/zod-to-openapi": "^6.3.1", - "@types/amqplib": "^0.10.5", - "@types/compression": "^1.7.5", - "@types/cors": "^2.8.15", - "@types/express": "^4.17.20", - "@types/jsonwebtoken": "^9.0.5", - "@types/supertest": "^6.0.2", - "@typescript-eslint/eslint-plugin": "^6.19.1", - "@typescript-eslint/parser": "^6.19.1", - "bun-types": "^1.0.35", - "eslint": "^8.56.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.1.3", - "husky": "^9.0.6", - "lint-staged": "^15.2.0", - "prettier": "^3.0.3", - "prettier-plugin-organize-imports": "^3.2.4", - "redoc-cli": "^0.13.21", - "supertest": "^6.3.4", - "typescript": "5.4" - } - }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@acuminous/bitsyntax": { - "version": "0.1.2", - "license": "MIT", - "dependencies": { - "buffer-more-ints": "~1.0.0", - "debug": "^4.3.4", - "safe-buffer": "~5.1.2" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@apm-js-collab/code-transformer": { - "version": "0.8.2", - "license": "Apache-2.0" - }, - "node_modules/@apm-js-collab/tracing-hooks": { - "version": "0.3.1", - "license": "Apache-2.0", - "dependencies": { - "@apm-js-collab/code-transformer": "^0.8.0", - "debug": "^4.4.1", - "module-details-from-path": "^1.0.4" - } - }, - "node_modules/@apm-js-collab/tracing-hooks/node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@asteasolutions/zod-to-openapi": { - "version": "6.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "openapi3-ts": "^4.1.2" - }, - "peerDependencies": { - "zod": "^3.20.2" - } - }, - "node_modules/@aws-crypto/crc32": { - "version": "5.2.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-crypto/crc32c": { - "version": "5.2.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/sha1-browser": { - "version": "5.2.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/supports-web-crypto": "^5.2.0", - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-utf8/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-utf8/node_modules/@smithy/util-buffer-from/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-browser": { - "version": "5.2.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-js": "^5.2.0", - "@aws-crypto/supports-web-crypto": "^5.2.0", - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8/node_modules/@smithy/util-buffer-from/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-js": { - "version": "5.2.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-crypto/supports-web-crypto": { - "version": "5.2.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/util": { - "version": "5.2.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8/node_modules/@smithy/util-buffer-from/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-s3": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha1-browser": "5.2.0", - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.908.0", - "@aws-sdk/credential-provider-node": "3.908.0", - "@aws-sdk/middleware-bucket-endpoint": "3.901.0", - "@aws-sdk/middleware-expect-continue": "3.901.0", - "@aws-sdk/middleware-flexible-checksums": "3.908.0", - "@aws-sdk/middleware-host-header": "3.901.0", - "@aws-sdk/middleware-location-constraint": "3.901.0", - "@aws-sdk/middleware-logger": "3.901.0", - "@aws-sdk/middleware-recursion-detection": "3.901.0", - "@aws-sdk/middleware-sdk-s3": "3.908.0", - "@aws-sdk/middleware-ssec": "3.901.0", - "@aws-sdk/middleware-user-agent": "3.908.0", - "@aws-sdk/region-config-resolver": "3.901.0", - "@aws-sdk/signature-v4-multi-region": "3.908.0", - "@aws-sdk/types": "3.901.0", - "@aws-sdk/util-endpoints": "3.901.0", - "@aws-sdk/util-user-agent-browser": "3.907.0", - "@aws-sdk/util-user-agent-node": "3.908.0", - "@aws-sdk/xml-builder": "3.901.0", - "@smithy/config-resolver": "^4.3.0", - "@smithy/core": "^3.15.0", - "@smithy/eventstream-serde-browser": "^4.2.0", - "@smithy/eventstream-serde-config-resolver": "^4.3.0", - "@smithy/eventstream-serde-node": "^4.2.0", - "@smithy/fetch-http-handler": "^5.3.1", - "@smithy/hash-blob-browser": "^4.2.1", - "@smithy/hash-node": "^4.2.0", - "@smithy/hash-stream-node": "^4.2.0", - "@smithy/invalid-dependency": "^4.2.0", - "@smithy/md5-js": "^4.2.0", - "@smithy/middleware-content-length": "^4.2.0", - "@smithy/middleware-endpoint": "^4.3.1", - "@smithy/middleware-retry": "^4.4.1", - "@smithy/middleware-serde": "^4.2.0", - "@smithy/middleware-stack": "^4.2.0", - "@smithy/node-config-provider": "^4.3.0", - "@smithy/node-http-handler": "^4.3.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/smithy-client": "^4.7.1", - "@smithy/types": "^4.6.0", - "@smithy/url-parser": "^4.2.0", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.0", - "@smithy/util-defaults-mode-node": "^4.2.1", - "@smithy/util-endpoints": "^3.2.0", - "@smithy/util-middleware": "^4.2.0", - "@smithy/util-retry": "^4.2.0", - "@smithy/util-stream": "^4.5.0", - "@smithy/util-utf8": "^4.2.0", - "@smithy/util-waiter": "^4.2.0", - "@smithy/uuid": "^1.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.908.0", - "@aws-sdk/middleware-host-header": "3.901.0", - "@aws-sdk/middleware-logger": "3.901.0", - "@aws-sdk/middleware-recursion-detection": "3.901.0", - "@aws-sdk/middleware-user-agent": "3.908.0", - "@aws-sdk/region-config-resolver": "3.901.0", - "@aws-sdk/types": "3.901.0", - "@aws-sdk/util-endpoints": "3.901.0", - "@aws-sdk/util-user-agent-browser": "3.907.0", - "@aws-sdk/util-user-agent-node": "3.908.0", - "@smithy/config-resolver": "^4.3.0", - "@smithy/core": "^3.15.0", - "@smithy/fetch-http-handler": "^5.3.1", - "@smithy/hash-node": "^4.2.0", - "@smithy/invalid-dependency": "^4.2.0", - "@smithy/middleware-content-length": "^4.2.0", - "@smithy/middleware-endpoint": "^4.3.1", - "@smithy/middleware-retry": "^4.4.1", - "@smithy/middleware-serde": "^4.2.0", - "@smithy/middleware-stack": "^4.2.0", - "@smithy/node-config-provider": "^4.3.0", - "@smithy/node-http-handler": "^4.3.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/smithy-client": "^4.7.1", - "@smithy/types": "^4.6.0", - "@smithy/url-parser": "^4.2.0", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.0", - "@smithy/util-defaults-mode-node": "^4.2.1", - "@smithy/util-endpoints": "^3.2.0", - "@smithy/util-middleware": "^4.2.0", - "@smithy/util-retry": "^4.2.0", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.901.0", - "@aws-sdk/xml-builder": "3.901.0", - "@smithy/core": "^3.15.0", - "@smithy/node-config-provider": "^4.3.0", - "@smithy/property-provider": "^4.2.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/signature-v4": "^5.3.0", - "@smithy/smithy-client": "^4.7.1", - "@smithy/types": "^4.6.0", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-middleware": "^4.2.0", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.908.0", - "@aws-sdk/types": "3.901.0", - "@smithy/property-provider": "^4.2.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.908.0", - "@aws-sdk/types": "3.901.0", - "@smithy/fetch-http-handler": "^5.3.1", - "@smithy/node-http-handler": "^4.3.0", - "@smithy/property-provider": "^4.2.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/smithy-client": "^4.7.1", - "@smithy/types": "^4.6.0", - "@smithy/util-stream": "^4.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.908.0", - "@aws-sdk/credential-provider-env": "3.908.0", - "@aws-sdk/credential-provider-http": "3.908.0", - "@aws-sdk/credential-provider-process": "3.908.0", - "@aws-sdk/credential-provider-sso": "3.908.0", - "@aws-sdk/credential-provider-web-identity": "3.908.0", - "@aws-sdk/nested-clients": "3.908.0", - "@aws-sdk/types": "3.901.0", - "@smithy/credential-provider-imds": "^4.2.0", - "@smithy/property-provider": "^4.2.0", - "@smithy/shared-ini-file-loader": "^4.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.908.0", - "@aws-sdk/credential-provider-http": "3.908.0", - "@aws-sdk/credential-provider-ini": "3.908.0", - "@aws-sdk/credential-provider-process": "3.908.0", - "@aws-sdk/credential-provider-sso": "3.908.0", - "@aws-sdk/credential-provider-web-identity": "3.908.0", - "@aws-sdk/types": "3.901.0", - "@smithy/credential-provider-imds": "^4.2.0", - "@smithy/property-provider": "^4.2.0", - "@smithy/shared-ini-file-loader": "^4.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.908.0", - "@aws-sdk/types": "3.901.0", - "@smithy/property-provider": "^4.2.0", - "@smithy/shared-ini-file-loader": "^4.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-sso": "3.908.0", - "@aws-sdk/core": "3.908.0", - "@aws-sdk/token-providers": "3.908.0", - "@aws-sdk/types": "3.901.0", - "@smithy/property-provider": "^4.2.0", - "@smithy/shared-ini-file-loader": "^4.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.908.0", - "@aws-sdk/nested-clients": "3.908.0", - "@aws-sdk/types": "3.901.0", - "@smithy/property-provider": "^4.2.0", - "@smithy/shared-ini-file-loader": "^4.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/middleware-bucket-endpoint": { - "version": "3.901.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.901.0", - "@aws-sdk/util-arn-parser": "3.893.0", - "@smithy/node-config-provider": "^4.3.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", - "@smithy/util-config-provider": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/middleware-expect-continue": { - "version": "3.901.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.901.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/middleware-flexible-checksums": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/crc32": "5.2.0", - "@aws-crypto/crc32c": "5.2.0", - "@aws-crypto/util": "5.2.0", - "@aws-sdk/core": "3.908.0", - "@aws-sdk/types": "3.901.0", - "@smithy/is-array-buffer": "^4.2.0", - "@smithy/node-config-provider": "^4.3.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", - "@smithy/util-middleware": "^4.2.0", - "@smithy/util-stream": "^4.5.0", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.901.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.901.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/middleware-location-constraint": { - "version": "3.901.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.901.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.901.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.901.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.901.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.901.0", - "@aws/lambda-invoke-store": "^0.0.1", - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.908.0", - "@aws-sdk/types": "3.901.0", - "@aws-sdk/util-arn-parser": "3.893.0", - "@smithy/core": "^3.15.0", - "@smithy/node-config-provider": "^4.3.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/signature-v4": "^5.3.0", - "@smithy/smithy-client": "^4.7.1", - "@smithy/types": "^4.6.0", - "@smithy/util-config-provider": "^4.2.0", - "@smithy/util-middleware": "^4.2.0", - "@smithy/util-stream": "^4.5.0", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/middleware-ssec": { - "version": "3.901.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.901.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.908.0", - "@aws-sdk/types": "3.901.0", - "@aws-sdk/util-endpoints": "3.901.0", - "@smithy/core": "^3.15.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/nested-clients": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.908.0", - "@aws-sdk/middleware-host-header": "3.901.0", - "@aws-sdk/middleware-logger": "3.901.0", - "@aws-sdk/middleware-recursion-detection": "3.901.0", - "@aws-sdk/middleware-user-agent": "3.908.0", - "@aws-sdk/region-config-resolver": "3.901.0", - "@aws-sdk/types": "3.901.0", - "@aws-sdk/util-endpoints": "3.901.0", - "@aws-sdk/util-user-agent-browser": "3.907.0", - "@aws-sdk/util-user-agent-node": "3.908.0", - "@smithy/config-resolver": "^4.3.0", - "@smithy/core": "^3.15.0", - "@smithy/fetch-http-handler": "^5.3.1", - "@smithy/hash-node": "^4.2.0", - "@smithy/invalid-dependency": "^4.2.0", - "@smithy/middleware-content-length": "^4.2.0", - "@smithy/middleware-endpoint": "^4.3.1", - "@smithy/middleware-retry": "^4.4.1", - "@smithy/middleware-serde": "^4.2.0", - "@smithy/middleware-stack": "^4.2.0", - "@smithy/node-config-provider": "^4.3.0", - "@smithy/node-http-handler": "^4.3.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/smithy-client": "^4.7.1", - "@smithy/types": "^4.6.0", - "@smithy/url-parser": "^4.2.0", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.0", - "@smithy/util-defaults-mode-node": "^4.2.1", - "@smithy/util-endpoints": "^3.2.0", - "@smithy/util-middleware": "^4.2.0", - "@smithy/util-retry": "^4.2.0", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.901.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.901.0", - "@smithy/node-config-provider": "^4.3.0", - "@smithy/types": "^4.6.0", - "@smithy/util-config-provider": "^4.2.0", - "@smithy/util-middleware": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/middleware-sdk-s3": "3.908.0", - "@aws-sdk/types": "3.901.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/signature-v4": "^5.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.908.0", - "@aws-sdk/nested-clients": "3.908.0", - "@aws-sdk/types": "3.901.0", - "@smithy/property-provider": "^4.2.0", - "@smithy/shared-ini-file-loader": "^4.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.901.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/util-arn-parser": { - "version": "3.893.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/util-endpoints": { - "version": "3.901.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.901.0", - "@smithy/types": "^4.6.0", - "@smithy/url-parser": "^4.2.0", - "@smithy/util-endpoints": "^3.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.893.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.907.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.901.0", - "@smithy/types": "^4.6.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.908.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/middleware-user-agent": "3.908.0", - "@aws-sdk/types": "3.901.0", - "@smithy/node-config-provider": "^4.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, - "node_modules/@aws-sdk/xml-builder": { - "version": "3.901.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0", - "fast-xml-parser": "5.2.5", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws/lambda-invoke-store": { - "version": "0.0.1", - "license": "Apache-2.0", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.24.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.24.2", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.24.1", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.24.3", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.1", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.1", - "@babel/parser": "^7.24.1", - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.24.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.23.6", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/compat-data": "^7.23.5", - "@babel/helper-validator-option": "^7.23.5", - "browserslist": "^4.22.2", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache/node_modules/yallist": { - "version": "3.1.1", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "peer": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.24.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.24.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.23.5", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.24.1", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles": { - "version": "3.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert": { - "version": "1.9.3", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/chalk/node_modules/ansi-styles/node_modules/color-convert/node_modules/color-name": { - "version": "1.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/@babel/highlight/node_modules/chalk/node_modules/escape-string-regexp": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk/node_modules/supports-color/node_modules/has-flag": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.24.1", - "dev": true, - "license": "MIT", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.24.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.24.1", - "dev": true, - "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.24.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.24.0", - "@babel/types": "^7.24.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.24.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.24.1", - "@babel/generator": "^7.24.1", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.24.1", - "@babel/types": "^7.24.0", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.24.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@clickhouse/client": { - "version": "1.5.0", - "license": "Apache-2.0", - "dependencies": { - "@clickhouse/client-common": "1.5.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@clickhouse/client-common": { - "version": "1.5.0", - "license": "Apache-2.0" - }, - "node_modules/@emotion/is-prop-valid": { - "version": "1.2.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@emotion/memoize": "^0.8.1" - } - }, - "node_modules/@emotion/memoize": { - "version": "0.8.1", - "dev": true, - "license": "MIT" - }, - "node_modules/@emotion/stylis": { - "version": "0.8.5", - "dev": true, - "license": "MIT" - }, - "node_modules/@emotion/unitless": { - "version": "0.7.5", - "dev": true, - "license": "MIT" - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@exodus/schemasafe": { - "version": "1.3.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", - "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/api-logs": { - "version": "0.204.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/context-async-hooks": { - "version": "2.2.0", - "license": "Apache-2.0", - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/core": { - "version": "2.2.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/instrumentation": { - "version": "0.204.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.204.0", - "import-in-the-middle": "^1.8.1", - "require-in-the-middle": "^7.1.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-amqplib": { - "version": "0.51.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-connect": { - "version": "0.48.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@types/connect": "3.4.38" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-dataloader": { - "version": "0.22.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.204.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-express": { - "version": "0.53.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-fs": { - "version": "0.24.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.204.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-generic-pool": { - "version": "0.48.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.204.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-graphql": { - "version": "0.52.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.204.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-hapi": { - "version": "0.51.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-http": { - "version": "0.204.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.1.0", - "@opentelemetry/instrumentation": "0.204.0", - "@opentelemetry/semantic-conventions": "^1.29.0", - "forwarded-parse": "2.1.2" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/core": { - "version": "2.1.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/instrumentation-ioredis": { - "version": "0.52.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/redis-common": "^0.38.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-kafkajs": { - "version": "0.14.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/semantic-conventions": "^1.30.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-knex": { - "version": "0.49.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/semantic-conventions": "^1.33.1" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-koa": { - "version": "0.52.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-lru-memoizer": { - "version": "0.49.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.204.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mongodb": { - "version": "0.57.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mongoose": { - "version": "0.51.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mysql": { - "version": "0.50.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@types/mysql": "2.15.27" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-mysql2": { - "version": "0.51.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@opentelemetry/sql-common": "^0.41.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-pg": { - "version": "0.57.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/semantic-conventions": "^1.34.0", - "@opentelemetry/sql-common": "^0.41.0", - "@types/pg": "8.15.5", - "@types/pg-pool": "2.0.6" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-pg/node_modules/@types/pg": { - "version": "8.15.5", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^2.2.0" - } - }, - "node_modules/@opentelemetry/instrumentation-redis": { - "version": "0.53.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/redis-common": "^0.38.0", - "@opentelemetry/semantic-conventions": "^1.27.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-tedious": { - "version": "0.23.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/semantic-conventions": "^1.27.0", - "@types/tedious": "^4.0.14" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-undici": { - "version": "0.15.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0", - "@opentelemetry/instrumentation": "^0.204.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.7.0" - } - }, - "node_modules/@opentelemetry/redis-common": { - "version": "0.38.2", - "license": "Apache-2.0", - "engines": { - "node": "^18.19.0 || >=20.6.0" - } - }, - "node_modules/@opentelemetry/resources": { - "version": "2.2.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.2.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.2.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.2.0", - "@opentelemetry/resources": "2.2.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.37.0", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@opentelemetry/sql-common": { - "version": "0.41.2", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^2.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0" - } - }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@prisma/instrumentation": { - "version": "6.15.0", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0 || ^0.57.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.8" - } - }, - "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/instrumentation": { - "version": "0.57.2", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.57.2", - "@types/shimmer": "^1.2.0", - "import-in-the-middle": "^1.8.1", - "require-in-the-middle": "^7.1.1", - "semver": "^7.5.2", - "shimmer": "^1.2.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@prisma/instrumentation/node_modules/@opentelemetry/instrumentation/node_modules/@opentelemetry/api-logs": { - "version": "0.57.2", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@redocly/ajv": { - "version": "8.11.0", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@redocly/ajv/node_modules/json-schema-traverse": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@redocly/config": { - "version": "0.1.5", - "dev": true, - "license": "MIT" - }, - "node_modules/@redocly/openapi-core": { - "version": "1.10.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@redocly/ajv": "^8.11.0", - "@redocly/config": "^0.1.4", - "colorette": "^1.2.0", - "js-levenshtein": "^1.1.6", - "js-yaml": "^4.1.0", - "lodash.isequal": "^4.5.0", - "minimatch": "^5.0.1", - "node-fetch": "^2.6.1", - "pluralize": "^8.0.0", - "yaml-ast-parser": "0.0.43" - }, - "engines": { - "node": ">=14.19.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@redocly/openapi-core/node_modules/colorette": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/@redocly/openapi-core/node_modules/minimatch": { - "version": "5.1.6", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@redocly/openapi-core/node_modules/minimatch/node_modules/brace-expansion": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@sentry/bun": { - "version": "10.23.0", - "license": "MIT", - "dependencies": { - "@sentry/core": "10.23.0", - "@sentry/node": "10.23.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@sentry/core": { - "version": "10.23.0", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@sentry/node": { - "version": "10.23.0", - "license": "MIT", - "dependencies": { - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^2.1.0", - "@opentelemetry/core": "^2.1.0", - "@opentelemetry/instrumentation": "^0.204.0", - "@opentelemetry/instrumentation-amqplib": "0.51.0", - "@opentelemetry/instrumentation-connect": "0.48.0", - "@opentelemetry/instrumentation-dataloader": "0.22.0", - "@opentelemetry/instrumentation-express": "0.53.0", - "@opentelemetry/instrumentation-fs": "0.24.0", - "@opentelemetry/instrumentation-generic-pool": "0.48.0", - "@opentelemetry/instrumentation-graphql": "0.52.0", - "@opentelemetry/instrumentation-hapi": "0.51.0", - "@opentelemetry/instrumentation-http": "0.204.0", - "@opentelemetry/instrumentation-ioredis": "0.52.0", - "@opentelemetry/instrumentation-kafkajs": "0.14.0", - "@opentelemetry/instrumentation-knex": "0.49.0", - "@opentelemetry/instrumentation-koa": "0.52.0", - "@opentelemetry/instrumentation-lru-memoizer": "0.49.0", - "@opentelemetry/instrumentation-mongodb": "0.57.0", - "@opentelemetry/instrumentation-mongoose": "0.51.0", - "@opentelemetry/instrumentation-mysql": "0.50.0", - "@opentelemetry/instrumentation-mysql2": "0.51.0", - "@opentelemetry/instrumentation-pg": "0.57.0", - "@opentelemetry/instrumentation-redis": "0.53.0", - "@opentelemetry/instrumentation-tedious": "0.23.0", - "@opentelemetry/instrumentation-undici": "0.15.0", - "@opentelemetry/resources": "^2.1.0", - "@opentelemetry/sdk-trace-base": "^2.1.0", - "@opentelemetry/semantic-conventions": "^1.37.0", - "@prisma/instrumentation": "6.15.0", - "@sentry/core": "10.23.0", - "@sentry/node-core": "10.23.0", - "@sentry/opentelemetry": "10.23.0", - "import-in-the-middle": "^1.14.2", - "minimatch": "^9.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@sentry/node-core": { - "version": "10.23.0", - "license": "MIT", - "dependencies": { - "@apm-js-collab/tracing-hooks": "^0.3.1", - "@sentry/core": "10.23.0", - "@sentry/opentelemetry": "10.23.0", - "import-in-the-middle": "^1.14.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0", - "@opentelemetry/core": "^1.30.1 || ^2.1.0", - "@opentelemetry/instrumentation": ">=0.57.1 <1", - "@opentelemetry/resources": "^1.30.1 || ^2.1.0", - "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", - "@opentelemetry/semantic-conventions": "^1.37.0" - } - }, - "node_modules/@sentry/node/node_modules/minimatch": { - "version": "9.0.3", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@sentry/node/node_modules/minimatch/node_modules/brace-expansion": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@sentry/opentelemetry": { - "version": "10.23.0", - "license": "MIT", - "dependencies": { - "@sentry/core": "10.23.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.1.0", - "@opentelemetry/core": "^1.30.1 || ^2.1.0", - "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", - "@opentelemetry/semantic-conventions": "^1.37.0" - } - }, - "node_modules/@smithy/abort-controller": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/chunked-blob-reader": { - "version": "5.2.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/chunked-blob-reader-native": { - "version": "4.2.1", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-base64": "^4.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/config-resolver": { - "version": "4.3.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.3.0", - "@smithy/types": "^4.6.0", - "@smithy/util-config-provider": "^4.2.0", - "@smithy/util-middleware": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/core": { - "version": "3.15.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/middleware-serde": "^4.2.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-middleware": "^4.2.0", - "@smithy/util-stream": "^4.5.0", - "@smithy/util-utf8": "^4.2.0", - "@smithy/uuid": "^1.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.3.0", - "@smithy/property-provider": "^4.2.0", - "@smithy/types": "^4.6.0", - "@smithy/url-parser": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/eventstream-codec": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/crc32": "5.2.0", - "@smithy/types": "^4.6.0", - "@smithy/util-hex-encoding": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-browser": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/eventstream-serde-universal": "^4.2.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-config-resolver": { - "version": "4.3.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-node": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/eventstream-serde-universal": "^4.2.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-universal": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/eventstream-codec": "^4.2.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "5.3.1", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.3.0", - "@smithy/querystring-builder": "^4.2.0", - "@smithy/types": "^4.6.0", - "@smithy/util-base64": "^4.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/hash-blob-browser": { - "version": "4.2.1", - "license": "Apache-2.0", - "dependencies": { - "@smithy/chunked-blob-reader": "^5.2.0", - "@smithy/chunked-blob-reader-native": "^4.2.1", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/hash-node": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0", - "@smithy/util-buffer-from": "^4.2.0", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/hash-stream-node": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/invalid-dependency": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/is-array-buffer": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/md5-js": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-content-length": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-endpoint": { - "version": "4.3.1", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.15.0", - "@smithy/middleware-serde": "^4.2.0", - "@smithy/node-config-provider": "^4.3.0", - "@smithy/shared-ini-file-loader": "^4.3.0", - "@smithy/types": "^4.6.0", - "@smithy/url-parser": "^4.2.0", - "@smithy/util-middleware": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-retry": { - "version": "4.4.1", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.3.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/service-error-classification": "^4.2.0", - "@smithy/smithy-client": "^4.7.1", - "@smithy/types": "^4.6.0", - "@smithy/util-middleware": "^4.2.0", - "@smithy/util-retry": "^4.2.0", - "@smithy/uuid": "^1.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-serde": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-stack": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/node-config-provider": { - "version": "4.3.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/property-provider": "^4.2.0", - "@smithy/shared-ini-file-loader": "^4.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "4.3.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/abort-controller": "^4.2.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/querystring-builder": "^4.2.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/property-provider": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/protocol-http": { - "version": "5.3.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/querystring-builder": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0", - "@smithy/util-uri-escape": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/querystring-parser": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/service-error-classification": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/shared-ini-file-loader": { - "version": "4.3.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "5.3.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^4.2.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", - "@smithy/util-hex-encoding": "^4.2.0", - "@smithy/util-middleware": "^4.2.0", - "@smithy/util-uri-escape": "^4.2.0", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/smithy-client": { - "version": "4.7.1", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.15.0", - "@smithy/middleware-endpoint": "^4.3.1", - "@smithy/middleware-stack": "^4.2.0", - "@smithy/protocol-http": "^5.3.0", - "@smithy/types": "^4.6.0", - "@smithy/util-stream": "^4.5.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "4.6.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/url-parser": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/querystring-parser": "^4.2.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-base64": { - "version": "4.3.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^4.2.0", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-body-length-browser": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-body-length-node": { - "version": "4.2.1", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-buffer-from": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-config-provider": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.3.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/property-provider": "^4.2.0", - "@smithy/smithy-client": "^4.7.1", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.2.1", - "license": "Apache-2.0", - "dependencies": { - "@smithy/config-resolver": "^4.3.0", - "@smithy/credential-provider-imds": "^4.2.0", - "@smithy/node-config-provider": "^4.3.0", - "@smithy/property-provider": "^4.2.0", - "@smithy/smithy-client": "^4.7.1", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-endpoints": { - "version": "3.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.3.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-hex-encoding": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-middleware": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-retry": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/service-error-classification": "^4.2.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-stream": { - "version": "4.5.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/fetch-http-handler": "^5.3.1", - "@smithy/node-http-handler": "^4.3.0", - "@smithy/types": "^4.6.0", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-buffer-from": "^4.2.0", - "@smithy/util-hex-encoding": "^4.2.0", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-uri-escape": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-utf8": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-waiter": { - "version": "4.2.0", - "license": "Apache-2.0", - "dependencies": { - "@smithy/abort-controller": "^4.2.0", - "@smithy/types": "^4.6.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/uuid": { - "version": "1.1.0", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@types/amqplib": { - "version": "0.10.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/compression": { - "version": "1.7.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/express": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/cookiejar": { - "version": "2.1.5", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/cors": { - "version": "2.8.17", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/eslint": { - "version": "8.56.6", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@types/express": { - "version": "4.17.21", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.43", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.4", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/jsonwebtoken": { - "version": "9.0.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/methods": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/mysql": { - "version": "2.15.27", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "20.11.30", - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/pg": { - "version": "8.15.6", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^2.2.0" - } - }, - "node_modules/@types/pg-pool": { - "version": "2.0.6", - "license": "MIT", - "dependencies": { - "@types/pg": "*" - } - }, - "node_modules/@types/pg-pool/node_modules/@types/pg": { - "version": "8.15.5", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^2.2.0" - } - }, - "node_modules/@types/qs": { - "version": "6.9.14", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/semver": { - "version": "7.5.8", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/send": { - "version": "0.17.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.5", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" - } - }, - "node_modules/@types/shimmer": { - "version": "1.2.0", - "license": "MIT" - }, - "node_modules/@types/superagent": { - "version": "8.1.6", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/cookiejar": "^2.1.5", - "@types/methods": "^1.1.4", - "@types/node": "*" - } - }, - "node_modules/@types/supertest": { - "version": "6.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/methods": "^1.1.4", - "@types/superagent": "^8.1.0" - } - }, - "node_modules/@types/tedious": { - "version": "4.0.14", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/ws": { - "version": "8.5.10", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules/brace-expansion": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "dev": true, - "license": "ISC" - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "dev": true, - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "dev": true, - "license": "Apache-2.0", - "peer": true - }, - "node_modules/accepts": { - "version": "1.3.8", - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.11.3", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "license": "MIT", - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "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/ajv-keywords": { - "version": "3.5.2", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/amqplib": { - "version": "0.10.3", - "license": "MIT", - "dependencies": { - "@acuminous/bitsyntax": "^0.1.2", - "buffer-more-ints": "~1.0.0", - "readable-stream": "1.x >=1.1.9", - "url-parse": "~1.5.10" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ansi-align": { - "version": "3.0.1", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.1.0" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "license": "MIT" - }, - "node_modules/array-union": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/asn1.js": { - "version": "4.10.1", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.0", - "dev": true, - "license": "MIT" - }, - "node_modules/assert": { - "version": "1.5.1", - "dev": true, - "license": "MIT", - "dependencies": { - "object.assign": "^4.1.4", - "util": "^0.10.4" - } - }, - "node_modules/assert/node_modules/util": { - "version": "0.10.4", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "2.0.3" - } - }, - "node_modules/assert/node_modules/util/node_modules/inherits": { - "version": "2.0.3", - "dev": true, - "license": "ISC" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/babel-plugin-styled-components": { - "version": "2.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", - "@babel/plugin-syntax-jsx": "^7.22.5", - "lodash": "^4.17.21", - "picomatch": "^2.3.1" - }, - "peerDependencies": { - "styled-components": ">= 2" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bintrees": { - "version": "1.0.2", - "license": "MIT" - }, - "node_modules/bn.js": { - "version": "5.2.1", - "dev": true, - "license": "MIT" - }, - "node_modules/body-parser": { - "version": "1.20.2", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/bowser": { - "version": "2.12.1", - "license": "MIT" - }, - "node_modules/boxen": { - "version": "5.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/wrap-ansi": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/boxen/node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/brorand": { - "version": "1.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/browserify-aes/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "node_modules/browserify-des": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/browserify-des/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/browserify-rsa": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "node_modules/browserify-sign": { - "version": "4.2.3", - "dev": true, - "license": "ISC", - "dependencies": { - "bn.js": "^5.2.1", - "browserify-rsa": "^4.1.0", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.5", - "hash-base": "~3.0", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.7", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/browserify-sign/node_modules/readable-stream": { - "version": "2.3.8", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/browserify-sign/node_modules/readable-stream/node_modules/isarray": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "dev": true, - "license": "MIT" - }, - "node_modules/browserify-sign/node_modules/readable-stream/node_modules/string_decoder": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/browserify-sign/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/browserify-zlib": { - "version": "0.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "pako": "~1.0.5" - } - }, - "node_modules/browserslist": { - "version": "4.23.0", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer": { - "version": "4.9.2", - "dev": true, - "license": "MIT", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "license": "BSD-3-Clause" - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/buffer-more-ints": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/buffer/node_modules/isarray": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/builtin-status-codes": { - "version": "3.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/bun-types": { - "version": "1.0.35", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "~20.11.3", - "@types/ws": "~8.5.10" - } - }, - "node_modules/bungie-net-core": { - "version": "2.1.3", - "license": "MIT" - }, - "node_modules/bytes": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind": { - "version": "1.0.7", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-me-maybe": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/callsites": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/camelize": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001600", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0", - "peer": true - }, - "node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "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/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/cipher-base": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/cipher-base/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/cjs-module-lexer": { - "version": "1.4.3", - "license": "MIT" - }, - "node_modules/classnames": { - "version": "2.5.1", - "dev": true, - "license": "MIT" - }, - "node_modules/cli-boxes": { - "version": "2.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-cursor": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate/node_modules/string-width": { - "version": "7.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate/node_modules/string-width/node_modules/emoji-regex": { - "version": "10.3.0", - "dev": true, - "license": "MIT" - }, - "node_modules/cli-truncate/node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/cli-truncate/node_modules/string-width/node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/cliui/node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/clsx": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/colorette": { - "version": "2.0.20", - "dev": true, - "license": "MIT" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "dev": true, - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "11.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - } - }, - "node_modules/component-emitter": { - "version": "1.3.1", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/compressible": { - "version": "2.0.18", - "license": "MIT", - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.7.4", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/compression/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/console-browserify": { - "version": "1.2.0", - "dev": true - }, - "node_modules/constants-browserify": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-disposition/node_modules/safe-buffer": { - "version": "5.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/content-type": { - "version": "1.0.5", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/cookie": { - "version": "0.6.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "license": "MIT" - }, - "node_modules/cookiejar": { - "version": "2.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/core-js": { - "version": "3.36.1", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "peer": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "license": "MIT" - }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.0", - "dev": true, - "license": "MIT" - }, - "node_modules/create-hash": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "dev": true, - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "node_modules/create-hmac/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/crypto-browserify": { - "version": "3.12.0", - "dev": true, - "license": "MIT", - "dependencies": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - }, - "engines": { - "node": "*" - } - }, - "node_modules/css-color-keywords": { - "version": "1.0.0", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=4" - } - }, - "node_modules/css-to-react-native": { - "version": "3.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "camelize": "^1.0.0", - "css-color-keywords": "^1.0.0", - "postcss-value-parser": "^4.0.2" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "license": "MIT" - }, - "node_modules/decko": { - "version": "1.2.0", - "dev": true - }, - "node_modules/deep-is": { - "version": "0.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/des.js": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/dezalgo": { - "version": "1.0.4", - "dev": true, - "license": "ISC", - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.0", - "dev": true, - "license": "MIT" - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/discord-api-types": { - "version": "0.38.47", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.47.tgz", - "integrity": "sha512-XgXQodHQBAE6kfD7kMvVo30863iHX1LHSqNq6MGUTDwIFCCvHva13+rwxyxVXDqudyApMNAd32PGjgVETi5rjA==", - "workspaces": [ - "scripts/actions/documentation" - ] - }, - "node_modules/doctrine": { - "version": "3.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/domain-browser": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4", - "npm": ">=1.2" - } - }, - "node_modules/dompurify": { - "version": "2.4.9", - "dev": true, - "license": "(MPL-2.0 OR Apache-2.0)" - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/ecdsa-sig-formatter/node_modules/safe-buffer": { - "version": "5.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.4.719", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/elliptic": { - "version": "6.5.5", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "dev": true, - "license": "MIT" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.16.0", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-module-lexer": { - "version": "1.5.0", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/es6-promise": { - "version": "3.3.1", - "dev": true, - "license": "MIT" - }, - "node_modules/escalade": { - "version": "3.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "dev": true, - "license": "MIT", - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.1.3", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "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/espree": { - "version": "9.6.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/events": { - "version": "3.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/evp_bytestokey/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/execa": { - "version": "8.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/express": { - "version": "4.19.2", - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.6.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/express/node_modules/safe-buffer": { - "version": "5.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-xml-parser": { - "version": "5.2.5", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT", - "dependencies": { - "strnum": "^2.1.0" - }, - "bin": { - "fxparser": "src/cli/cli.js" - } - }, - "node_modules/fastq": { - "version": "1.17.1", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/find-up": { - "version": "5.0.0", - "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": "3.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "dev": true, - "license": "ISC" - }, - "node_modules/foreach": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/form-data": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/formidable": { - "version": "2.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "dezalgo": "^1.0.4", - "hexoid": "^1.0.0", - "once": "^1.4.0", - "qs": "^6.11.0" - }, - "funding": { - "url": "https://ko-fi.com/tunnckoCore/commissions" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/forwarded-parse": { - "version": "2.1.2", - "license": "MIT" - }, - "node_modules/fresh": { - "version": "0.5.2", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stream": { - "version": "8.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "dev": true, - "license": "BSD-2-Clause", - "peer": true - }, - "node_modules/globals": { - "version": "13.24.0", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "dev": true, - "license": "ISC", - "peer": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/handlebars": { - "version": "4.7.8", - "dev": true, - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hash-base": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hash-base/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/hash.js": { - "version": "1.1.7", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hexoid": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "dev": true, - "license": "MIT" - }, - "node_modules/http-errors": { - "version": "2.0.0", - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http2-client": { - "version": "1.3.5", - "dev": true, - "license": "MIT" - }, - "node_modules/https-browserify": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/human-signals": { - "version": "5.0.0", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/husky": { - "version": "9.0.11", - "dev": true, - "license": "MIT", - "bin": { - "husky": "bin.mjs" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/ignore": { - "version": "5.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-in-the-middle": { - "version": "1.15.0", - "license": "Apache-2.0", - "dependencies": { - "acorn": "^8.14.0", - "acorn-import-attributes": "^1.9.5", - "cjs-module-lexer": "^1.2.2", - "module-details-from-path": "^1.0.3" - } - }, - "node_modules/import-in-the-middle/node_modules/acorn": { - "version": "8.15.0", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "license": "ISC" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "0.0.1", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/js-levenshtein": { - "version": "1.1.6", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/json-pointer": { - "version": "0.6.2", - "dev": true, - "license": "MIT", - "dependencies": { - "foreach": "^2.0.4" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonwebtoken": { - "version": "9.0.2", - "license": "MIT", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - } - }, - "node_modules/jwa": { - "version": "1.4.1", - "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jwa/node_modules/safe-buffer": { - "version": "5.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/jws": { - "version": "3.2.2", - "license": "MIT", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws/node_modules/safe-buffer": { - "version": "5.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/keyv": { - "version": "4.5.4", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lilconfig": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/lint-staged": { - "version": "15.2.2", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "5.3.0", - "commander": "11.1.0", - "debug": "4.3.4", - "execa": "8.0.1", - "lilconfig": "3.0.0", - "listr2": "8.0.1", - "micromatch": "4.0.5", - "pidtree": "0.6.0", - "string-argv": "0.3.2", - "yaml": "2.3.4" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, - "engines": { - "node": ">=18.12.0" - }, - "funding": { - "url": "https://opencollective.com/lint-staged" - } - }, - "node_modules/lint-staged/node_modules/chalk": { - "version": "5.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/listr2": { - "version": "8.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "cli-truncate": "^4.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.0.0", - "rfdc": "^1.3.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/loader-runner": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "license": "MIT" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "license": "MIT" - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "license": "MIT" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "license": "MIT" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "license": "MIT" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "license": "MIT" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.once": { - "version": "4.1.1", - "license": "MIT" - }, - "node_modules/log-update": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^6.2.0", - "cli-cursor": "^4.0.0", - "slice-ansi": "^7.0.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/ansi-escapes": { - "version": "6.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-update/node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/strip-ansi": { - "version": "7.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/lunr": { - "version": "2.3.9", - "dev": true, - "license": "MIT" - }, - "node_modules/mark.js": { - "version": "8.11.1", - "dev": true, - "license": "MIT" - }, - "node_modules/marked": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/md5.js": { - "version": "1.3.5", - "dev": true, - "license": "MIT", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/md5.js/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/media-typer": { - "version": "0.3.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "license": "MIT" - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.0", - "dev": true, - "license": "MIT" - }, - "node_modules/mime": { - "version": "2.6.0", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "dev": true, - "license": "ISC" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mobx": { - "version": "6.12.1", - "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mobx" - } - }, - "node_modules/mobx-react": { - "version": "7.6.0", - "dev": true, - "license": "MIT", - "dependencies": { - "mobx-react-lite": "^3.4.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mobx" - }, - "peerDependencies": { - "mobx": "^6.1.0", - "react": "^16.8.0 || ^17 || ^18" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, - "node_modules/mobx-react-lite": { - "version": "3.4.3", - "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mobx" - }, - "peerDependencies": { - "mobx": "^6.1.0", - "react": "^16.8.0 || ^17 || ^18" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, - "node_modules/module-details-from-path": { - "version": "1.0.4", - "license": "MIT" - }, - "node_modules/ms": { - "version": "2.1.3", - "license": "MIT" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "dev": true, - "license": "MIT" - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-fetch-h2": { - "version": "2.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "http2-client": "^1.2.5" - }, - "engines": { - "node": "4.x || >=6.0.0" - } - }, - "node_modules/node-libs-browser": { - "version": "2.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" - } - }, - "node_modules/node-libs-browser/node_modules/readable-stream": { - "version": "2.3.8", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/node-libs-browser/node_modules/readable-stream/node_modules/isarray": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/node-libs-browser/node_modules/readable-stream/node_modules/string_decoder": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/node-readfiles": { - "version": "0.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "es6-promise": "^3.2.1" - } - }, - "node_modules/node-releases": { - "version": "2.0.14", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "5.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/oas-kit-common": { - "version": "1.0.8", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "fast-safe-stringify": "^2.0.7" - } - }, - "node_modules/oas-linter": { - "version": "3.2.2", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@exodus/schemasafe": "^1.0.0-rc.2", - "should": "^13.2.1", - "yaml": "^1.10.0" - }, - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/oas-linter/node_modules/yaml": { - "version": "1.10.2", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, - "node_modules/oas-resolver": { - "version": "2.5.6", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "node-fetch-h2": "^2.3.0", - "oas-kit-common": "^1.0.8", - "reftools": "^1.1.9", - "yaml": "^1.10.0", - "yargs": "^17.0.1" - }, - "bin": { - "resolve": "resolve.js" - }, - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/oas-resolver/node_modules/yaml": { - "version": "1.10.2", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, - "node_modules/oas-schema-walker": { - "version": "1.1.5", - "dev": true, - "license": "BSD-3-Clause", - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/oas-validator": { - "version": "5.0.8", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "call-me-maybe": "^1.0.1", - "oas-kit-common": "^1.0.8", - "oas-linter": "^3.2.2", - "oas-resolver": "^2.5.6", - "oas-schema-walker": "^1.1.5", - "reftools": "^1.1.9", - "should": "^13.2.1", - "yaml": "^1.10.0" - }, - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/oas-validator/node_modules/yaml": { - "version": "1.10.2", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.0.2", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/openapi-sampler": { - "version": "1.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.7", - "json-pointer": "0.6.2" - } - }, - "node_modules/openapi3-ts": { - "version": "4.2.2", - "dev": true, - "license": "MIT", - "dependencies": { - "yaml": "^2.3.4" - } - }, - "node_modules/optionator": { - "version": "0.9.3", - "dev": true, - "license": "MIT", - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/os-browserify": { - "version": "0.3.0", - "dev": true, - "license": "MIT" - }, - "node_modules/p-limit": { - "version": "3.1.0", - "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", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "dev": true, - "license": "(MIT AND Zlib)" - }, - "node_modules/parent-module": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-asn1": { - "version": "5.1.7", - "dev": true, - "license": "ISC", - "dependencies": { - "asn1.js": "^4.10.1", - "browserify-aes": "^1.2.0", - "evp_bytestokey": "^1.0.3", - "hash-base": "~3.0", - "pbkdf2": "^3.1.2", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/parse-asn1/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/parseurl": { - "version": "1.3.3", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-browserify": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/path-exists": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "license": "MIT" - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "license": "MIT" - }, - "node_modules/path-type": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pbkdf2": { - "version": "3.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/pbkdf2/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/perfect-scrollbar": { - "version": "1.5.5", - "dev": true, - "license": "MIT" - }, - "node_modules/pg": { - "version": "8.16.3", - "license": "MIT", - "dependencies": { - "pg-connection-string": "^2.9.1", - "pg-pool": "^3.10.1", - "pg-protocol": "^1.10.3", - "pg-types": "2.2.0", - "pgpass": "1.0.5" - }, - "engines": { - "node": ">= 16.0.0" - }, - "optionalDependencies": { - "pg-cloudflare": "^1.2.7" - }, - "peerDependencies": { - "pg-native": ">=3.0.1" - }, - "peerDependenciesMeta": { - "pg-native": { - "optional": true - } - } - }, - "node_modules/pg-cloudflare": { - "version": "1.2.7", - "license": "MIT", - "optional": true - }, - "node_modules/pg-connection-string": { - "version": "2.9.1", - "license": "MIT" - }, - "node_modules/pg-int8": { - "version": "1.0.1", - "license": "ISC", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/pg-pool": { - "version": "3.10.1", - "license": "MIT", - "peerDependencies": { - "pg": ">=8.0" - } - }, - "node_modules/pg-protocol": { - "version": "1.10.3", - "license": "MIT" - }, - "node_modules/pg-types": { - "version": "2.2.0", - "license": "MIT", - "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pg-types/node_modules/postgres-array": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/pg-types/node_modules/postgres-bytea": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pgpass": { - "version": "1.0.5", - "license": "MIT", - "dependencies": { - "split2": "^4.1.0" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pidtree": { - "version": "0.6.0", - "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/pluralize": { - "version": "8.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/polished": { - "version": "4.3.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.17.8" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/postgres-date": { - "version": "1.0.7", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-interval": { - "version": "1.2.0", - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.2.5", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/prettier-plugin-organize-imports": { - "version": "3.2.4", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@volar/vue-language-plugin-pug": "^1.0.4", - "@volar/vue-typescript": "^1.0.4", - "prettier": ">=2.0", - "typescript": ">=2.9" - }, - "peerDependenciesMeta": { - "@volar/vue-language-plugin-pug": { - "optional": true - }, - "@volar/vue-typescript": { - "optional": true - } - } - }, - "node_modules/prismjs": { - "version": "1.29.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/process": { - "version": "0.11.10", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/prom-client": { - "version": "15.1.1", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.4.0", - "tdigest": "^0.1.1" - }, - "engines": { - "node": "^16 || ^18 || >=20" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "dev": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "dev": true, - "license": "MIT" - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.0", - "dev": true, - "license": "MIT" - }, - "node_modules/public-encrypt/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/punycode": { - "version": "1.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/qs": { - "version": "6.11.0", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystring-es3": { - "version": "0.2.1", - "dev": true, - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "license": "MIT" - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/randombytes": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/randombytes/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/randomfill": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "node_modules/randomfill/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/range-parser": { - "version": "1.2.1", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.2", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/react": { - "version": "17.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "17.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { - "react": "17.0.2" - } - }, - "node_modules/react-is": { - "version": "18.2.0", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/react-tabs": { - "version": "3.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "clsx": "^1.1.0", - "prop-types": "^15.5.0" - }, - "peerDependencies": { - "react": "^16.3.0 || ^17.0.0-0" - } - }, - "node_modules/readable-stream": { - "version": "1.1.14", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/readable-stream/node_modules/string_decoder": { - "version": "0.10.31", - "license": "MIT" - }, - "node_modules/readdirp": { - "version": "3.6.0", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/redoc": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@redocly/openapi-core": "^1.0.0-beta.104", - "classnames": "^2.3.1", - "decko": "^1.2.0", - "dompurify": "^2.2.8", - "eventemitter3": "^4.0.7", - "json-pointer": "^0.6.2", - "lunr": "^2.3.9", - "mark.js": "^8.11.1", - "marked": "^4.0.15", - "mobx-react": "^7.2.0", - "openapi-sampler": "^1.3.0", - "path-browserify": "^1.0.1", - "perfect-scrollbar": "^1.5.5", - "polished": "^4.1.3", - "prismjs": "^1.27.0", - "prop-types": "^15.7.2", - "react-tabs": "^3.2.2", - "slugify": "~1.4.7", - "stickyfill": "^1.1.1", - "style-loader": "^3.3.1", - "swagger2openapi": "^7.0.6", - "url-template": "^2.0.8" - }, - "engines": { - "node": ">=6.9", - "npm": ">=3.0.0" - }, - "peerDependencies": { - "core-js": "^3.1.4", - "mobx": "^6.0.4", - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0", - "styled-components": "^4.1.1 || ^5.1.1" - } - }, - "node_modules/redoc-cli": { - "version": "0.13.21", - "dev": true, - "license": "MIT", - "dependencies": { - "boxen": "5.1.2", - "chokidar": "^3.5.1", - "handlebars": "^4.7.7", - "mkdirp": "^1.0.4", - "mobx": "^6.3.2", - "node-libs-browser": "^2.2.1", - "react": "^17.0.1", - "react-dom": "^17.0.1", - "redoc": "2.0.0", - "styled-components": "^5.3.0", - "yargs": "^17.3.1" - }, - "bin": { - "redoc-cli": "index.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/redoc/node_modules/eventemitter3": { - "version": "4.0.7", - "dev": true, - "license": "MIT" - }, - "node_modules/redoc/node_modules/path-browserify": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/reftools": { - "version": "1.1.9", - "dev": true, - "license": "BSD-3-Clause", - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "dev": true, - "license": "MIT" - }, - "node_modules/require-directory": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-in-the-middle": { - "version": "7.5.2", - "license": "MIT", - "dependencies": { - "debug": "^4.3.5", - "module-details-from-path": "^1.0.3", - "resolve": "^1.22.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/require-in-the-middle/node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/resolve": { - "version": "1.22.11", - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/restore-cursor": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor/node_modules/onetime": { - "version": "5.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor/node_modules/onetime/node_modules/mimic-fn": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "3.0.7", - "dev": true, - "license": "ISC" - }, - "node_modules/reusify": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rfdc": { - "version": "1.3.1", - "dev": true, - "license": "MIT" - }, - "node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/ripemd160": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "license": "MIT" - }, - "node_modules/scheduler": { - "version": "0.20.2", - "dev": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/schema-utils": { - "version": "3.3.0", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/semver": { - "version": "7.6.0", - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.18.0", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/send/node_modules/mime": { - "version": "1.6.0", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-static": { - "version": "1.15.0", - "license": "MIT", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "dev": true, - "license": "MIT" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "license": "ISC" - }, - "node_modules/sha.js": { - "version": "2.4.11", - "dev": true, - "license": "(MIT AND BSD-3-Clause)", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, - "node_modules/sha.js/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/shallowequal": { - "version": "1.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/shimmer": { - "version": "1.2.1", - "license": "BSD-2-Clause" - }, - "node_modules/should": { - "version": "13.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "should-equal": "^2.0.0", - "should-format": "^3.0.3", - "should-type": "^1.4.0", - "should-type-adaptors": "^1.0.1", - "should-util": "^1.0.0" - } - }, - "node_modules/should-equal": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "should-type": "^1.4.0" - } - }, - "node_modules/should-format": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "should-type": "^1.3.0", - "should-type-adaptors": "^1.0.1" - } - }, - "node_modules/should-type": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/should-type-adaptors": { - "version": "1.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "should-type": "^1.3.0", - "should-util": "^1.0.0" - } - }, - "node_modules/should-util": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/side-channel": { - "version": "1.0.6", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/slugify": { - "version": "1.4.7", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split2": { - "version": "4.2.0", - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stickyfill": { - "version": "1.1.1", - "dev": true - }, - "node_modules/stream-browserify": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "node_modules/stream-browserify/node_modules/readable-stream": { - "version": "2.3.8", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/stream-browserify/node_modules/readable-stream/node_modules/isarray": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/stream-browserify/node_modules/readable-stream/node_modules/string_decoder": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/stream-http": { - "version": "2.8.3", - "dev": true, - "license": "MIT", - "dependencies": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - } - }, - "node_modules/stream-http/node_modules/readable-stream": { - "version": "2.3.8", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/stream-http/node_modules/readable-stream/node_modules/isarray": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/stream-http/node_modules/readable-stream/node_modules/string_decoder": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/string-argv": { - "version": "0.3.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.19" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strnum": { - "version": "2.1.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - } - ], - "license": "MIT" - }, - "node_modules/style-loader": { - "version": "3.3.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/styled-components": { - "version": "5.3.11", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/traverse": "^7.4.5", - "@emotion/is-prop-valid": "^1.1.0", - "@emotion/stylis": "^0.8.4", - "@emotion/unitless": "^0.7.4", - "babel-plugin-styled-components": ">= 1.12.0", - "css-to-react-native": "^3.0.0", - "hoist-non-react-statics": "^3.0.0", - "shallowequal": "^1.1.0", - "supports-color": "^5.5.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/styled-components" - }, - "peerDependencies": { - "react": ">= 16.8.0", - "react-dom": ">= 16.8.0", - "react-is": ">= 16.8.0" - } - }, - "node_modules/styled-components/node_modules/supports-color": { - "version": "5.5.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/styled-components/node_modules/supports-color/node_modules/has-flag": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/superagent": { - "version": "8.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.4", - "debug": "^4.3.4", - "fast-safe-stringify": "^2.1.1", - "form-data": "^4.0.0", - "formidable": "^2.1.2", - "methods": "^1.1.2", - "mime": "2.6.0", - "qs": "^6.11.0", - "semver": "^7.3.8" - }, - "engines": { - "node": ">=6.4.0 <13 || >=14" - } - }, - "node_modules/supertest": { - "version": "6.3.4", - "dev": true, - "license": "MIT", - "dependencies": { - "methods": "^1.1.2", - "superagent": "^8.1.2" - }, - "engines": { - "node": ">=6.4.0" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/swagger2openapi": { - "version": "7.0.8", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "call-me-maybe": "^1.0.1", - "node-fetch": "^2.6.1", - "node-fetch-h2": "^2.3.0", - "node-readfiles": "^0.2.0", - "oas-kit-common": "^1.0.8", - "oas-resolver": "^2.5.6", - "oas-schema-walker": "^1.1.5", - "oas-validator": "^5.0.8", - "reftools": "^1.1.9", - "yaml": "^1.10.0", - "yargs": "^17.0.1" - }, - "bin": { - "boast": "boast.js", - "oas-validate": "oas-validate.js", - "swagger2openapi": "swagger2openapi.js" - }, - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/swagger2openapi/node_modules/yaml": { - "version": "1.10.2", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, - "node_modules/synckit": { - "version": "0.8.8", - "dev": true, - "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/synckit/node_modules/tslib": { - "version": "2.6.2", - "dev": true, - "license": "0BSD" - }, - "node_modules/tapable": { - "version": "2.2.1", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/tdigest": { - "version": "0.1.2", - "license": "MIT", - "dependencies": { - "bintrees": "1.0.2" - } - }, - "node_modules/terser": { - "version": "5.30.0", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/jest-worker": { - "version": "27.5.1", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/terser-webpack-plugin/node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/terser/node_modules/source-map-support": { - "version": "0.5.21", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/timers-browserify": { - "version": "2.0.12", - "dev": true, - "license": "MIT", - "dependencies": { - "setimmediate": "^1.0.4" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/to-arraybuffer": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/tslib": { - "version": "2.7.0", - "license": "0BSD" - }, - "node_modules/tty-browserify": { - "version": "0.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/type-check": { - "version": "0.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "5.4.5", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/uglify-js": { - "version": "3.17.4", - "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.13", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uri-js/node_modules/punycode": { - "version": "2.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/url": { - "version": "0.11.3", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^1.4.1", - "qs": "^6.11.2" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "license": "MIT", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/url-template": { - "version": "2.0.8", - "dev": true, - "license": "BSD" - }, - "node_modules/url/node_modules/qs": { - "version": "6.12.0", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/util": { - "version": "0.11.1", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "2.0.3" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/util/node_modules/inherits": { - "version": "2.0.3", - "dev": true, - "license": "ISC" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vm-browserify": { - "version": "1.1.2", - "dev": true, - "license": "MIT" - }, - "node_modules/watchpack": { - "version": "2.4.1", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/webpack": { - "version": "5.91.0", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.21.10", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.16.0", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "5.1.1", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/webpack/node_modules/eslint-scope/node_modules/estraverse": { - "version": "4.3.0", - "dev": true, - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/widest-line": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi": { - "version": "9.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "7.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/wrap-ansi/node_modules/string-width/node_modules/emoji-regex": { - "version": "10.3.0", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "dev": true, - "license": "ISC" - }, - "node_modules/xtend": { - "version": "4.0.2", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "license": "ISC" - }, - "node_modules/yaml": { - "version": "2.3.4", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 14" - } - }, - "node_modules/yaml-ast-parser": { - "version": "0.0.43", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/yargs": { - "version": "17.7.2", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "3.22.4", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} From b2d9841659adc119a8695d5ce80344ffd53f4c54 Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 09:46:36 -0400 Subject: [PATCH 04/22] fixes --- open-api/openapi.json | 822 +++++++++++++++++- package.json | 2 - scripts/discord/sync-commands.ts | 87 -- src/core/RaidHubRoute.ts | 54 -- src/index.ts | 4 - src/integrations/discord/command-registry.ts | 244 ------ src/integrations/discord/interactions.ts | 208 ----- src/integrations/discord/message-builders.ts | 28 - src/integrations/discord/response-registry.ts | 205 ----- src/integrations/discord/types.ts | 45 - 10 files changed, 821 insertions(+), 878 deletions(-) delete mode 100644 scripts/discord/sync-commands.ts delete mode 100644 src/integrations/discord/command-registry.ts delete mode 100644 src/integrations/discord/interactions.ts delete mode 100644 src/integrations/discord/message-builders.ts delete mode 100644 src/integrations/discord/response-registry.ts delete mode 100644 src/integrations/discord/types.ts diff --git a/open-api/openapi.json b/open-api/openapi.json index 4a0f77fc..fd2b5986 100644 --- a/open-api/openapi.json +++ b/open-api/openapi.json @@ -42,6 +42,7 @@ "AdminQuerySyntaxError", "InsufficientPermissionsError", "InvalidClientSecretError", + "InvalidDiscordAuthError", "InternalServerError", "ServiceUnavailableError", "BungieServiceOffline" @@ -1771,6 +1772,232 @@ "estimatedBacklogEmptied" ] }, + "DiscordWebhookBody": { + "type": "object", + "default": {}, + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 80 + }, + "filters": { + "type": "object", + "properties": { + "requireFresh": { + "type": "boolean" + }, + "requireCompleted": { + "type": "boolean" + } + } + }, + "targets": { + "type": "object", + "properties": { + "playerMembershipIds": { + "type": "array", + "items": { + "type": "string", + "pattern": "^\\d+$" + } + }, + "clanGroupIds": { + "type": "array", + "items": { + "type": "string", + "pattern": "^\\d+$" + } + } + } + } + } + }, + "DiscordWebhookPutResponse": { + "type": "object", + "properties": { + "guildId": { + "type": "string" + }, + "channelId": { + "type": "string" + }, + "webhookId": { + "type": "string" + }, + "webhookUrl": { + "type": "string", + "format": "uri" + }, + "created": { + "type": "boolean" + }, + "activated": { + "type": "boolean" + }, + "updated": { + "type": "boolean" + }, + "rules": { + "type": "object", + "properties": { + "players": { + "type": "object", + "properties": { + "inserted": { + "type": "integer", + "minimum": 0 + }, + "updated": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["inserted", "updated"] + }, + "clans": { + "type": "object", + "properties": { + "inserted": { + "type": "integer", + "minimum": 0 + }, + "updated": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["inserted", "updated"] + } + }, + "required": ["players", "clans"] + } + }, + "required": [ + "guildId", + "channelId", + "webhookId", + "created", + "activated", + "updated", + "rules" + ] + }, + "DiscordWebhookDeleteResponse": { + "type": "object", + "properties": { + "deleted": { + "type": "boolean" + } + }, + "required": ["deleted"] + }, + "DiscordWebhookStatusResponse": { + "oneOf": [ + { + "type": "object", + "properties": { + "registered": { + "type": "boolean", + "enum": [false] + } + }, + "required": ["registered"] + }, + { + "type": "object", + "properties": { + "registered": { + "type": "boolean", + "enum": [true] + }, + "guildId": { + "type": "string" + }, + "channelId": { + "type": "string" + }, + "webhookId": { + "type": "string" + }, + "destinationActive": { + "type": "boolean" + }, + "consecutiveDeliveryFailures": { + "type": "integer", + "minimum": 0 + }, + "lastDeliverySuccessAt": { + "type": "string", + "nullable": true + }, + "lastDeliveryFailureAt": { + "type": "string", + "nullable": true + }, + "lastDeliveryError": { + "type": "string", + "nullable": true + }, + "players": { + "type": "array", + "items": { + "type": "object", + "properties": { + "membershipId": { + "type": "string", + "pattern": "^\\d+$" + }, + "requireFresh": { + "type": "boolean" + }, + "requireCompleted": { + "type": "boolean" + } + }, + "required": [ + "membershipId", + "requireFresh", + "requireCompleted" + ] + } + }, + "clans": { + "type": "array", + "items": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "pattern": "^\\d+$" + }, + "requireFresh": { + "type": "boolean" + }, + "requireCompleted": { + "type": "boolean" + } + }, + "required": ["groupId", "requireFresh", "requireCompleted"] + } + } + }, + "required": [ + "registered", + "guildId", + "channelId", + "webhookId", + "destinationActive", + "consecutiveDeliveryFailures", + "lastDeliverySuccessAt", + "lastDeliveryFailureAt", + "lastDeliveryError", + "players", + "clans" + ] + } + ] + }, "ManifestResponse": { "type": "object", "properties": { @@ -1992,11 +2219,16 @@ "minimum": 0, "exclusiveMinimum": true }, + "offset": { + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true + }, "query": { "type": "string" } }, - "required": ["count", "query"] + "required": ["count", "offset", "query"] }, "results": { "type": "array", @@ -3129,6 +3361,112 @@ } }, "required": ["value", "expires"] + }, + "SubscriptionsDiscordWebhooksResponse": { + "oneOf": [ + { + "type": "object", + "properties": { + "registered": { + "type": "boolean", + "enum": [false] + } + }, + "required": ["registered"] + }, + { + "type": "object", + "properties": { + "registered": { + "type": "boolean", + "enum": [true] + }, + "guildId": { + "type": "string" + }, + "channelId": { + "type": "string" + }, + "webhookId": { + "type": "string" + }, + "destinationActive": { + "type": "boolean" + }, + "consecutiveDeliveryFailures": { + "type": "integer", + "minimum": 0 + }, + "lastDeliverySuccessAt": { + "type": "string", + "nullable": true + }, + "lastDeliveryFailureAt": { + "type": "string", + "nullable": true + }, + "lastDeliveryError": { + "type": "string", + "nullable": true + }, + "players": { + "type": "array", + "items": { + "type": "object", + "properties": { + "membershipId": { + "type": "string", + "pattern": "^\\d+$" + }, + "requireFresh": { + "type": "boolean" + }, + "requireCompleted": { + "type": "boolean" + } + }, + "required": [ + "membershipId", + "requireFresh", + "requireCompleted" + ] + } + }, + "clans": { + "type": "array", + "items": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "pattern": "^\\d+$" + }, + "requireFresh": { + "type": "boolean" + }, + "requireCompleted": { + "type": "boolean" + } + }, + "required": ["groupId", "requireFresh", "requireCompleted"] + } + } + }, + "required": [ + "registered", + "guildId", + "channelId", + "webhookId", + "destinationActive", + "consecutiveDeliveryFailures", + "lastDeliverySuccessAt", + "lastDeliveryFailureAt", + "lastDeliveryError", + "players", + "clans" + ] + } + ] } }, "parameters": {}, @@ -3373,6 +3711,19 @@ "name": "count", "in": "query" }, + { + "schema": { + "type": "integer", + "nullable": true, + "minimum": 0, + "maximum": 5000, + "default": 0, + "description": "Number of leading search hits to skip (for pagination). Must be 0 when count is the full result window." + }, + "required": false, + "name": "offset", + "in": "query" + }, { "schema": { "type": "string", @@ -8120,6 +8471,475 @@ } } } + }, + "/subscriptions/discord/webhooks": { + "get": { + "description": "Get RaidHub subscription webhook status for the current channel (no secrets).", + "summary": "/subscriptions/discord/webhooks", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [true] + }, + "response": { + "$ref": "#/components/schemas/SubscriptionsDiscordWebhooksResponse" + } + }, + "required": ["minted", "success", "response"] + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["ApiKeyError"] + }, + "error": { + "$ref": "#/components/schemas/ApiKeyError" + } + }, + "required": ["minted", "success", "code", "error"] + } + } + } + }, + "403": { + "description": "InsufficientPermissionsError", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["InsufficientPermissionsError"] + }, + "error": { + "$ref": "#/components/schemas/InsufficientPermissionsError" + } + }, + "required": ["minted", "success", "code", "error"] + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["InternalServerError"] + }, + "error": { + "$ref": "#/components/schemas/InternalServerError" + } + }, + "required": ["minted", "success", "code", "error"] + } + } + } + } + } + }, + "put": { + "description": "Create or update the RaidHub subscription webhook for this channel (idempotent upsert).", + "summary": "/subscriptions/discord/webhooks", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DiscordWebhookBody" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [true] + }, + "response": { + "allOf": [ + { + "$ref": "#/components/schemas/SubscriptionsDiscordWebhooksResponse" + }, + { + "type": "object", + "properties": { + "guildId": { + "type": "string" + }, + "channelId": { + "type": "string" + }, + "webhookId": { + "type": "string" + }, + "webhookUrl": { + "type": "string", + "format": "uri" + }, + "created": { + "type": "boolean" + }, + "activated": { + "type": "boolean" + }, + "updated": { + "type": "boolean" + }, + "rules": { + "type": "object", + "properties": { + "players": { + "type": "object", + "properties": { + "inserted": { + "type": "integer", + "minimum": 0 + }, + "updated": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["inserted", "updated"] + }, + "clans": { + "type": "object", + "properties": { + "inserted": { + "type": "integer", + "minimum": 0 + }, + "updated": { + "type": "integer", + "minimum": 0 + } + }, + "required": ["inserted", "updated"] + } + }, + "required": ["players", "clans"] + } + }, + "required": [ + "guildId", + "channelId", + "webhookId", + "created", + "activated", + "updated", + "rules" + ] + } + ] + } + }, + "required": ["minted", "success", "response"] + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["BodyValidationError"] + }, + "error": { + "$ref": "#/components/schemas/BodyValidationError" + } + }, + "required": ["minted", "success", "code", "error"] + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["ApiKeyError"] + }, + "error": { + "$ref": "#/components/schemas/ApiKeyError" + } + }, + "required": ["minted", "success", "code", "error"] + } + } + } + }, + "403": { + "description": "InsufficientPermissionsError", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["InsufficientPermissionsError"] + }, + "error": { + "$ref": "#/components/schemas/InsufficientPermissionsError" + } + }, + "required": ["minted", "success", "code", "error"] + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["InternalServerError"] + }, + "error": { + "$ref": "#/components/schemas/InternalServerError" + } + }, + "required": ["minted", "success", "code", "error"] + } + } + } + } + } + }, + "delete": { + "description": "Delete a Discord subscription webhook registration for the current channel.", + "summary": "/subscriptions/discord/webhooks", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [true] + }, + "response": { + "allOf": [ + { + "$ref": "#/components/schemas/SubscriptionsDiscordWebhooksResponse" + }, + { + "type": "object", + "properties": { + "deleted": { + "type": "boolean" + } + }, + "required": ["deleted"] + } + ] + } + }, + "required": ["minted", "success", "response"] + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["ApiKeyError"] + }, + "error": { + "$ref": "#/components/schemas/ApiKeyError" + } + }, + "required": ["minted", "success", "code", "error"] + } + } + } + }, + "403": { + "description": "InsufficientPermissionsError", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["InsufficientPermissionsError"] + }, + "error": { + "$ref": "#/components/schemas/InsufficientPermissionsError" + } + }, + "required": ["minted", "success", "code", "error"] + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["InternalServerError"] + }, + "error": { + "$ref": "#/components/schemas/InternalServerError" + } + }, + "required": ["minted", "success", "code", "error"] + } + } + } + } + } + } } } } diff --git a/package.json b/package.json index a6eec9c7..a9ca172c 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,6 @@ "lint": "eslint . --ext .ts", "format": "prettier '**/*.{ts,json}'", "docs": "bun run ./open-api/generate.ts", - "discord:sync-commands": "bun run ./scripts/discord/sync-commands.ts", "compile": "bun build --compile --sourcemap ./src/index.ts --outfile $1" }, "lint-staged": { @@ -58,7 +57,6 @@ "amqplib": "^0.10.3", "bungie-net-core": "2.1.3", "compression": "^1.7.4", - "discord-api-types": "^0.38.47", "express": "^4.18.2", "jsonwebtoken": "^9.0.2", "pg": "^8.16.3", diff --git a/scripts/discord/sync-commands.ts b/scripts/discord/sync-commands.ts deleted file mode 100644 index f4c7eecf..00000000 --- a/scripts/discord/sync-commands.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { deriveDiscordCommandOptions, collectDiscordExposedRoutes } from "@/integrations/discord/command-registry" -import { router } from "@/routes/index" -import { ApplicationCommandOptionType, ApplicationCommandType } from "discord-api-types/v10" - -type DiscordCommandPayload = { - name: string - description: string - type: ApplicationCommandType.ChatInput - options?: { - type: - | ApplicationCommandOptionType.String - | ApplicationCommandOptionType.Integer - | ApplicationCommandOptionType.Boolean - | ApplicationCommandOptionType.Number - name: string - description: string - required: boolean - }[] -} - -const getEnv = (key: string) => { - const value = process.env[key]?.trim() - if (!value) { - throw new Error(`${key} is required`) - } - return value -} - -const toPayload = (): DiscordCommandPayload[] => { - const entries = [...collectDiscordExposedRoutes(router).values()] - return entries - .map(entry => ({ - name: entry.commandName.toLowerCase().slice(0, 32), - description: (entry.description || `Run ${entry.commandName}`).slice(0, 100), - type: ApplicationCommandType.ChatInput as const, - options: deriveDiscordCommandOptions(entry.route) - })) - .sort((a, b) => a.name.localeCompare(b.name)) -} - -const applicationId = getEnv("DISCORD_APPLICATION_ID") -const botToken = getEnv("DISCORD_BOT_TOKEN") -const guildId = process.env.DISCORD_GUILD_ID?.trim() -const dryRun = process.env.DISCORD_SYNC_DRY_RUN === "true" - -const endpoint = guildId - ? `https://discord.com/api/v10/applications/${applicationId}/guilds/${guildId}/commands` - : `https://discord.com/api/v10/applications/${applicationId}/commands` - -const payload = toPayload() - -if (dryRun) { - console.log( - JSON.stringify( - { - target: guildId ? `guild:${guildId}` : "global", - endpoint, - commands: payload - }, - null, - 2 - ) - ) - process.exit(0) -} - -try { - const response = await fetch(endpoint, { - method: "PUT", - headers: { - Authorization: `Bot ${botToken}`, - "Content-Type": "application/json" - }, - body: JSON.stringify(payload) - }) - - if (!response.ok) { - const details = await response.text() - throw new Error(`Discord command sync failed (${response.status}): ${details}`) - } - - console.log(`Synced ${payload.length} Discord command(s) to ${guildId ? "guild" : "global"} scope.`) - process.exit(0) -} catch (error) { - console.error(error instanceof Error ? error.message : String(error)) - process.exit(1) -} diff --git a/src/core/RaidHubRoute.ts b/src/core/RaidHubRoute.ts index 2f814d95..d5c8763a 100644 --- a/src/core/RaidHubRoute.ts +++ b/src/core/RaidHubRoute.ts @@ -282,60 +282,6 @@ export class RaidHubRoute< return this.parent ? this.parent.getFullPath(this) : "/" } - getDerivedRouteId() { - const normalizedPath = this.getFullPath() - .replace(/\/+/g, "/") - .replace(/^\/|\/$/g, "") - .replace(/:(\w+)/g, "{$1}") - return `${this.method.toUpperCase()} ${normalizedPath || "/"}` - } - - async invoke( - req: { - params?: unknown - query?: unknown - body?: unknown - headers?: IncomingHttpHeaders - auth?: import("@/auth/jwt").JWTAuthContext - discord?: import("@/integrations/discord/context-jwt").DiscordInvocationContext - } = {}, - after?: (callback: () => Promise) => void - ) { - const callbacks: (() => Promise)[] = [] - const result = await this.handler( - { - params: this.paramsSchema?.parse(req.params) ?? {}, - query: this.querySchema?.parse(req.query ?? {}) ?? {}, - body: this.bodySchema?.parse(req.body) ?? {}, - headers: req.headers ?? {}, - auth: req.auth, - discord: req.discord - }, - callback => { - callbacks.push(callback) - after?.(callback) - } - ) - - for (const callback of callbacks) { - try { - await callback() - } catch (err) { - logger.error( - "ROUTE_AFTER_CALLBACK_ERROR", - err instanceof Error ? err : new Error(String(err)), - { - path: this.getFullPath(), - method: this.method.toUpperCase(), - mode: "invoke" - } - ) - } - } - - return result - } - deprecatedCopy() { return new RaidHubRoute({ isDeprecated: true, diff --git a/src/index.ts b/src/index.ts index 59a2f001..d6135130 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,7 +7,6 @@ import path from "path" import { verifyApiKey } from "./auth/api-keys" import { attachDiscordContext } from "./auth/discord-context" import { attachUserAuth } from "./auth/user-context" -import { discordInteractionsRouter } from "./integrations/discord/interactions" import { servePrometheus } from "./integrations/prometheus/server" import { Logger } from "./lib/utils/logging" import { errorHandler } from "./middleware/error-handler" @@ -46,9 +45,6 @@ app.options("*", (req, res) => { res.sendStatus(204) }) -// Discord validates signatures against raw request bytes. -app.use("/integrations/discord", express.raw({ type: "*/*" }), discordInteractionsRouter) - // parse incoming request body with json, apply the router, handle any uncaught errors app.use( verifyApiKey, diff --git a/src/integrations/discord/command-registry.ts b/src/integrations/discord/command-registry.ts deleted file mode 100644 index 3855cf1e..00000000 --- a/src/integrations/discord/command-registry.ts +++ /dev/null @@ -1,244 +0,0 @@ -import { RaidHubRoute } from "@/core/RaidHubRoute" -import { RaidHubRouter } from "@/core/RaidHubRouter" -import { IRaidHubRoute } from "@/core/RaidHubRouterTypes" -import { instanceRoute } from "@/routes/instance" -import { playerSearchRoute } from "@/routes/player/search" -import { ApplicationCommandOptionType } from "discord-api-types/v10" -import { z } from "zod" -import { signDiscordInvocationContext } from "./context-jwt" -import { DiscordApiStyleRequest, DiscordInteraction, DiscordInteractionDataOption } from "./types" - -type AnyRaidHubRoute = RaidHubRoute< - "get" | "post" | "patch" | "put" | "delete", - z.ZodTypeAny, - any, - any, - any, - any -> - -const discordEnabledRoutes = new Set([instanceRoute, playerSearchRoute]) - -export type DiscordExposedRoute = { - commandName: string - route: AnyRaidHubRoute - description: string - routeId: string -} - -const snakeCase = (input: string) => - input - .replace(/([a-z0-9])([A-Z])/g, "$1_$2") - .replace(/[\s-]+/g, "_") - .toLowerCase() - -const commandNameFromPath = (fullPath: string) => { - const segments = fullPath - .split("/") - .filter(Boolean) - .filter(segment => !segment.startsWith(":")) - .map(segment => segment.replace(/[^a-zA-Z0-9_-]/g, "").toLowerCase()) - .filter(Boolean) - return (segments.join("-") || "command").slice(0, 32) -} - -const commandDescriptionFromRoute = (description: string, commandName: string) => { - const normalized = description.replace(/\s+/g, " ").trim() - if (!normalized) return `Run ${commandName}`.slice(0, 100) - return normalized.slice(0, 100) -} - -const flattenRoutes = (node: IRaidHubRoute): AnyRaidHubRoute[] => { - if (node instanceof RaidHubRoute) return [node as AnyRaidHubRoute] - if (node instanceof RaidHubRouter) { - return node.routes.flatMap(({ route }) => - Array.isArray(route) - ? route.flatMap(child => flattenRoutes(child)) - : flattenRoutes(route) - ) - } - return [] -} - -export const collectDiscordExposedRoutes = ( - root: RaidHubRouter -): Map => { - const routes = flattenRoutes(root) - const exposed = routes - .map(route => ({ - route, - routeId: route.getDerivedRouteId() - })) - .filter(item => discordEnabledRoutes.has(item.route)) - - const byCommand = new Map() - for (const { route, routeId } of exposed) { - const commandName = commandNameFromPath(route.getFullPath()) - byCommand.set(commandName, { - commandName, - route, - routeId, - description: commandDescriptionFromRoute(route.description, commandName) - }) - } - return byCommand -} - -const flattenCommandOptions = (options: DiscordInteractionDataOption[] = []) => { - const flattened: [string, string | number | boolean][] = [] - for (const option of options ?? []) { - if (typeof option.value !== "undefined") { - flattened.push([option.name, option.value]) - } - if (option.options && option.options.length > 0) { - flattened.push(...flattenCommandOptions(option.options)) - } - } - return flattened -} - -const getCommandOptionMap = (interaction: DiscordInteraction) => - Object.fromEntries(flattenCommandOptions(interaction.data?.options)) - -const camelCase = (value: string) => - value.replace(/_([a-z])/g, (_, letter: string) => letter.toUpperCase()) - -const getZodObjectShape = (schema: z.ZodTypeAny | null): Record => { - if (!(schema instanceof z.ZodObject)) return {} - return schema.shape as Record -} - -const getRouteShapes = (route: AnyRaidHubRoute) => ({ - params: getZodObjectShape(route.paramsSchema), - query: getZodObjectShape(route.querySchema), - body: getZodObjectShape(route.bodySchema) -}) - -const inferOptionTarget = ( - route: AnyRaidHubRoute, - field: string -): "params" | "query" | "body" => { - const shapes = getRouteShapes(route) - if (field in shapes.params) return "params" - if (field in shapes.query) return "query" - return "body" -} - -export const buildRouteInvocationRequest = ( - interaction: DiscordInteraction, - exposedRoute: DiscordExposedRoute, - headers: Record = {} -): DiscordApiStyleRequest => { - const rawOptions = getCommandOptionMap(interaction) - const params: Record = {} - const query: Record = {} - const body: Record = {} - - for (const [optionName, value] of Object.entries(rawOptions)) { - const field = camelCase(optionName) - const target = inferOptionTarget(exposedRoute.route, field) - - if (target === "params") params[field] = value - else if (target === "query") query[field] = value - else body[field] = value - } - - const contextJwt = signDiscordInvocationContext({ - interactionId: interaction.id, - commandName: exposedRoute.commandName, - routeId: exposedRoute.routeId, - userId: interaction.member?.user?.id ?? "", - guildId: interaction.guild_id, - channelId: interaction.channel_id - }) - - return { - params, - query, - body: Object.keys(body).length > 0 ? body : null, - headers: { - authorization: `Discord ${contextJwt}`, - ...headers - } - } -} - -export const deriveDiscordOptionNames = (route: AnyRaidHubRoute) => { - return deriveDiscordCommandOptions(route).map(option => option.name) -} - -type DiscordApplicationCommandOption = { - type: - | ApplicationCommandOptionType.String - | ApplicationCommandOptionType.Integer - | ApplicationCommandOptionType.Boolean - | ApplicationCommandOptionType.Number - name: string - description: string - required: boolean -} - -const inferDiscordOptionType = ( - schema: z.ZodTypeAny -): - | ApplicationCommandOptionType.String - | ApplicationCommandOptionType.Integer - | ApplicationCommandOptionType.Boolean - | ApplicationCommandOptionType.Number => { - let current = schema - while (true) { - if (current instanceof z.ZodOptional || current instanceof z.ZodNullable) { - current = current.unwrap() as z.ZodTypeAny - continue - } - if (current instanceof z.ZodDefault || current instanceof z.ZodCatch) { - current = current._def.innerType as z.ZodTypeAny - continue - } - if (current instanceof z.ZodEffects) { - current = current.innerType() - continue - } - break - } - - if (current instanceof z.ZodBoolean) return ApplicationCommandOptionType.Boolean - if (current instanceof z.ZodNumber) { - return current.isInt - ? ApplicationCommandOptionType.Integer - : ApplicationCommandOptionType.Number - } - if (current instanceof z.ZodNativeEnum) { - const values = Object.values(current.enum as Record) - if (values.some(value => typeof value === "number")) { - return ApplicationCommandOptionType.Integer - } - } - return ApplicationCommandOptionType.String -} - -export const deriveDiscordCommandOptions = ( - route: AnyRaidHubRoute -): DiscordApplicationCommandOption[] => { - const shapes = getRouteShapes(route) - const options = new Map() - - const addShapeOptions = (shape: Record) => { - for (const [key, schema] of Object.entries(shape)) { - const optionName = snakeCase(key).slice(0, 32) - if (options.has(optionName)) continue - options.set(optionName, { - type: inferDiscordOptionType(schema), - name: optionName, - description: `Value for ${optionName}`.slice(0, 100), - required: false - }) - } - } - - addShapeOptions(shapes.params) - addShapeOptions(shapes.query) - addShapeOptions(shapes.body) - - return [...options.values()] -} diff --git a/src/integrations/discord/interactions.ts b/src/integrations/discord/interactions.ts deleted file mode 100644 index ca476282..00000000 --- a/src/integrations/discord/interactions.ts +++ /dev/null @@ -1,208 +0,0 @@ -import { Router } from "express" -import { createPublicKey, verify } from "crypto" -import { InteractionResponseType, InteractionType } from "discord-api-types/v10" -import { Logger } from "@/lib/utils/logging" -import { router as rootRouter } from "@/routes/index" -import { ErrorCode } from "@/schema/errors/ErrorCode" -import { - buildRouteInvocationRequest, - collectDiscordExposedRoutes, - deriveDiscordOptionNames -} from "./command-registry" -import { - mapDiscordComponentInteraction, - mapDiscordKnownError, - mapDiscordSuccess -} from "./response-registry" -import { DiscordComponentsV2Response, DiscordInteraction } from "./types" - -const SIGNATURE_WINDOW_MS = 5 * 60 * 1000 -const logger = new Logger("DISCORD_INTERACTIONS") - -const toDiscordPublicKey = (hex: string) => { - const raw = Buffer.from(hex, "hex") - const derHeader = Buffer.from("302a300506032b6570032100", "hex") - return createPublicKey({ - key: Buffer.concat([derHeader, raw]), - format: "der", - type: "spki" - }) -} - -const verifyDiscordSignature = (args: { - timestamp: string - signatureHex: string - rawBody: Buffer -}): boolean => { - const publicKeyHex = process.env.DISCORD_PUBLIC_KEY - if (!publicKeyHex) return false - - const timestampMs = Number(args.timestamp) * 1000 - if (!Number.isFinite(timestampMs) || Math.abs(Date.now() - timestampMs) > SIGNATURE_WINDOW_MS) { - return false - } - - const message = Buffer.concat([Buffer.from(args.timestamp), args.rawBody]) - const signature = Buffer.from(args.signatureHex, "hex") - return verify(null, message, toDiscordPublicKey(publicKeyHex), signature) -} - -const toComponentsResponse = (content: string): DiscordComponentsV2Response => ({ - type: InteractionResponseType.ChannelMessageWithSource, - data: { - content - } -}) - -const interactionAppId = () => { - const value = process.env.DISCORD_APPLICATION_ID?.trim() - if (!value) throw new Error("DISCORD_APPLICATION_ID is required for deferred command responses") - return value -} - -const patchOriginalInteractionResponse = async ( - interaction: DiscordInteraction, - message: DiscordComponentsV2Response["data"] -) => { - const applicationId = interaction.application_id ?? interactionAppId() - const response = await fetch( - `https://discord.com/api/v10/webhooks/${applicationId}/${interaction.token}/messages/@original`, - { - method: "PATCH", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify(message) - } - ) - - if (!response.ok) { - const detail = await response.text() - throw new Error(`Failed to update interaction response (${response.status}): ${detail}`) - } -} - -export const discordInteractionsRouter = Router() - -discordInteractionsRouter.post("/interactions", async (req, res) => { - const signature = req.header("X-Signature-Ed25519") - const timestamp = req.header("X-Signature-Timestamp") - const rawBody = Buffer.isBuffer(req.body) ? req.body : Buffer.from("") - - if (!signature || !timestamp || !verifyDiscordSignature({ signatureHex: signature, timestamp, rawBody })) { - res.status(401).json({ - minted: new Date(), - success: false, - code: ErrorCode.InvalidDiscordAuthError, - error: { - message: "Invalid Discord signature" - } - }) - return - } - - const interaction = JSON.parse(rawBody.toString("utf8")) as DiscordInteraction - if (interaction.type === InteractionType.Ping) { - res.status(200).json({ type: InteractionResponseType.Pong }) - return - } - - if (interaction.type === InteractionType.MessageComponent) { - const updated = mapDiscordComponentInteraction(interaction) - if (!updated) { - res.status(400).json(toComponentsResponse("Unsupported interaction component")) - return - } - res.status(200).json({ - type: InteractionResponseType.UpdateMessage, - data: updated - }) - return - } - - if (interaction.type !== InteractionType.ApplicationCommand || !interaction.data?.name) { - res.status(400).json(toComponentsResponse("Unsupported interaction type")) - return - } - - const commandMap = collectDiscordExposedRoutes(rootRouter) - const binding = commandMap.get(interaction.data.name) - - if (!binding) { - res.status(200).json(toComponentsResponse("This command is not enabled yet.")) - return - } - - const processCommand = async () => { - const apiRequest = buildRouteInvocationRequest(interaction, binding) - let result: Awaited> - try { - result = await binding.route.invoke(apiRequest) - } catch (err) { - logger.error( - "DISCORD_ROUTE_INVOKE_FAILED", - err instanceof Error ? err : new Error(String(err)), - { - command: binding.commandName, - route_id: binding.routeId - } - ) - await patchOriginalInteractionResponse( - interaction, - toComponentsResponse(`Execution failed for \`${binding.commandName}\`.`).data - ) - return - } - - if (result.success) { - const mapped = mapDiscordSuccess(binding, result) - if (mapped) { - await patchOriginalInteractionResponse(interaction, mapped) - return - } - await patchOriginalInteractionResponse( - interaction, - toComponentsResponse(`Success for \`${binding.commandName}\` (${binding.routeId})`).data - ) - return - } - - const mappedError = mapDiscordKnownError(binding, result) - if (mappedError) { - await patchOriginalInteractionResponse(interaction, mappedError) - return - } - await patchOriginalInteractionResponse( - interaction, - toComponentsResponse(`Request failed with \`${result.code}\` while running \`${binding.commandName}\`.`).data - ) - } - - res.status(200).json({ - type: InteractionResponseType.DeferredChannelMessageWithSource - }) - - void processCommand().catch(async () => { - try { - const knownOptions = deriveDiscordOptionNames(binding.route) - const receivedOptions = (interaction.data?.options ?? []) - .map(option => option.name) - .join(", ") - await patchOriginalInteractionResponse( - interaction, - toComponentsResponse( - `Unable to run \`${binding.commandName}\`. Expected options: ${knownOptions.join(", ")}. Received: ${receivedOptions || "none"}.` - ).data - ) - } catch (err) { - logger.error( - "DISCORD_COMMAND_RESPONSE_FAILED", - err instanceof Error ? err : new Error(String(err)), - { - command: binding.commandName, - route_id: binding.routeId - } - ) - } - }) -}) diff --git a/src/integrations/discord/message-builders.ts b/src/integrations/discord/message-builders.ts deleted file mode 100644 index ba626100..00000000 --- a/src/integrations/discord/message-builders.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { DiscordComponentsV2Response } from "./types" - -type DiscordEmbedField = { - name: string - value: string - inline?: boolean -} - -type DiscordEmbed = { - title?: string - description?: string - fields?: DiscordEmbedField[] - color?: number - timestamp?: string -} - -type DiscordMessageData = DiscordComponentsV2Response["data"] & { - embeds?: DiscordEmbed[] -} - -export const buildDiscordContentMessage = (content: string): DiscordMessageData => ({ - content -}) - -export const buildDiscordEmbedMessage = (embed: DiscordEmbed): DiscordMessageData => ({ - embeds: [embed] -}) - diff --git a/src/integrations/discord/response-registry.ts b/src/integrations/discord/response-registry.ts deleted file mode 100644 index 52184475..00000000 --- a/src/integrations/discord/response-registry.ts +++ /dev/null @@ -1,205 +0,0 @@ -import { buildDiscordContentMessage, buildDiscordEmbedMessage } from "./message-builders" -import { DiscordExposedRoute } from "./command-registry" -import { DiscordComponentsV2Response, DiscordInteraction } from "./types" -import { ButtonStyle, ComponentType, InteractionType } from "discord-api-types/v10" -import { playerSearchRoute } from "@/routes/player/search" -import { ErrorCode } from "@/schema/errors/ErrorCode" -import { zInstanceExtended } from "@/schema/components/InstanceExtended" -import { randomUUID } from "crypto" -import { z } from "zod" - -type DiscordInvocationSuccess = { success: true; response: unknown } -type DiscordInvocationFailure = { success: false; code: string; error: unknown } - -type DiscordResponseMapper = { - mapSuccess?: (response: unknown) => DiscordComponentsV2Response["data"] - mapKnownErrors?: Partial DiscordComponentsV2Response["data"]>> -} - -const formatDuration = (seconds: number) => { - const h = Math.floor(seconds / 3600) - const m = Math.floor((seconds % 3600) / 60) - const s = seconds % 60 - return `${h}h ${m}m ${s}s` -} - -const formatInstanceDiscordSummary = (response: z.infer) => - buildDiscordEmbedMessage({ - title: response.metadata.activityName, - description: `Instance \`${response.instanceId}\``, - color: 0x5865f2, - fields: [ - { name: "Version", value: response.metadata.versionName, inline: true }, - { name: "Players", value: String(response.playerCount), inline: true }, - { name: "Duration", value: formatDuration(response.duration), inline: true }, - { name: "Completed", value: response.completed ? "Yes" : "No", inline: true }, - { name: "Fresh", value: response.fresh ? "Yes" : "No", inline: true }, - { name: "Flawless", value: response.flawless ? "Yes" : "No", inline: true }, - { - name: "Completed At", - value: - response.dateCompleted instanceof Date - ? response.dateCompleted.toISOString() - : String(response.dateCompleted), - inline: false - } - ] - }) - -type PlayerSearchResponse = z.infer -type PlayerSearchPagerState = { - createdAt: number - response: PlayerSearchResponse -} -const PLAYER_SEARCH_PAGE_SIZE = 5 -const PLAYER_SEARCH_PAGER_TTL_MS = 10 * 60 * 1000 -const PLAYER_SEARCH_PAGER_PREFIX = "ps" -const playerSearchPager = new Map() - -const putPlayerSearchPagerState = (response: PlayerSearchResponse) => { - const id = randomUUID().replace(/-/g, "").slice(0, 16) - playerSearchPager.set(id, { - createdAt: Date.now(), - response - }) - return id -} - -const getPlayerSearchPagerState = (id: string) => { - const state = playerSearchPager.get(id) - if (!state) return null - if (Date.now() - state.createdAt > PLAYER_SEARCH_PAGER_TTL_MS) { - playerSearchPager.delete(id) - return null - } - return state -} - -const clamp = (value: number, min: number, max: number) => Math.max(min, Math.min(max, value)) - -const formatPlayerName = (player: PlayerSearchResponse["results"][number]) => { - if (player.bungieGlobalDisplayName) { - const code = player.bungieGlobalDisplayNameCode ? `#${player.bungieGlobalDisplayNameCode}` : "" - return `${player.bungieGlobalDisplayName}${code}` - } - return player.displayName ?? "Unknown Player" -} - -const parsePlayerSearchButtonId = (customId: string) => { - const parts = customId.split(":") - if (parts.length !== 3) return null - if (parts[0] !== PLAYER_SEARCH_PAGER_PREFIX) return null - const page = Number(parts[2]) - if (!Number.isInteger(page)) return null - return { - stateId: parts[1], - page - } -} - -const renderPlayerSearchSummary = (response: PlayerSearchResponse, stateId: string, page: number) => { - if (response.results.length === 0 || page < 0) { - return buildDiscordContentMessage(`No players found for \`${response.params.query}\`.`) - } - - const totalPages = Math.max(1, Math.ceil(response.results.length / PLAYER_SEARCH_PAGE_SIZE)) - const currentPage = clamp(page, 0, totalPages - 1) - const start = currentPage * PLAYER_SEARCH_PAGE_SIZE - const preview = response.results.slice(start, start + PLAYER_SEARCH_PAGE_SIZE) - const lines = preview.map((player, idx) => { - const membershipType = player.membershipType === null ? "unknown" : String(player.membershipType) - return `${start + idx + 1}. **${formatPlayerName(player)}** (\`${player.membershipId}\`, type ${membershipType})` - }) - - const message = buildDiscordEmbedMessage({ - title: "Player Search Results", - description: - `Query: \`${response.params.query}\`\n` + - `Page ${currentPage + 1}/${totalPages} - showing ${preview.length}/${response.results.length} result(s).`, - color: 0x57f287, - fields: [ - { - name: "Matches", - value: lines.join("\n"), - inline: false - } - ] - }) - - return { - ...message, - components: [ - { - type: ComponentType.ActionRow, - components: [ - { - type: ComponentType.Button, - style: ButtonStyle.Secondary, - custom_id: `${PLAYER_SEARCH_PAGER_PREFIX}:${stateId}:${currentPage - 1}`, - label: "Prev", - disabled: currentPage <= 0 - }, - { - type: ComponentType.Button, - style: ButtonStyle.Secondary, - custom_id: `${PLAYER_SEARCH_PAGER_PREFIX}:${stateId}:${currentPage + 1}`, - label: "Next", - disabled: currentPage >= totalPages - 1 - } - ] - } - ] - } -} - -const formatPlayerSearchSummary = (rawResponse: unknown) => { - const response = playerSearchRoute.responseSchema.parse(rawResponse) - const stateId = putPlayerSearchPagerState(response) - return renderPlayerSearchSummary(response, stateId, 0) -} - -const discordResponseByCommandName: Record = { - instance: { - mapSuccess: response => formatInstanceDiscordSummary(response as z.infer), - mapKnownErrors: { - [ErrorCode.InstanceNotFoundError]: () => buildDiscordContentMessage("Instance not found.") - } - }, - "player-search": { - mapSuccess: response => formatPlayerSearchSummary(response) - } -} - -export const getDiscordResponseMapper = (binding: DiscordExposedRoute): DiscordResponseMapper => { - return discordResponseByCommandName[binding.commandName] ?? {} -} - -export const mapDiscordSuccess = ( - binding: DiscordExposedRoute, - result: DiscordInvocationSuccess -): DiscordComponentsV2Response["data"] | null => { - return getDiscordResponseMapper(binding).mapSuccess?.(result.response) ?? null -} - -export const mapDiscordKnownError = ( - binding: DiscordExposedRoute, - result: DiscordInvocationFailure -): DiscordComponentsV2Response["data"] | null => { - return getDiscordResponseMapper(binding).mapKnownErrors?.[result.code]?.(result.error) ?? null -} - -export const mapDiscordComponentInteraction = ( - interaction: DiscordInteraction -): DiscordComponentsV2Response["data"] | null => { - if (interaction.type !== InteractionType.MessageComponent) return null - const customId = interaction.data?.custom_id ?? null - if (!customId) return null - const parsed = parsePlayerSearchButtonId(customId) - if (!parsed) return null - const state = getPlayerSearchPagerState(parsed.stateId) - if (!state) { - return buildDiscordContentMessage("This player search session expired. Run the command again.") - } - return renderPlayerSearchSummary(state.response, parsed.stateId, parsed.page) -} - diff --git a/src/integrations/discord/types.ts b/src/integrations/discord/types.ts deleted file mode 100644 index da36fdbb..00000000 --- a/src/integrations/discord/types.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { ApplicationCommandOptionType, InteractionResponseType, InteractionType } from "discord-api-types/v10" -import { IncomingHttpHeaders } from "http" - -export type DiscordInteractionDataOption = { - name: string - type: ApplicationCommandOptionType - value?: string | number | boolean - options?: DiscordInteractionDataOption[] -} - -export type DiscordInteraction = { - id: string - application_id?: string - type: InteractionType - token: string - guild_id?: string - channel_id?: string - member?: { - user?: { - id: string - } - } - data?: { - id?: string - name?: string - options?: DiscordInteractionDataOption[] - custom_id?: string - } -} - -export type DiscordApiStyleRequest = { - params: Record - query: Record - body: unknown - headers: IncomingHttpHeaders -} - -export type DiscordComponentsV2Response = { - type: InteractionResponseType.ChannelMessageWithSource - data: { - flags?: number - content?: string - components?: unknown[] - } -} From 3df7e294e8969efa485994b75d2e8dcae1eb18d8 Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 21:00:11 -0400 Subject: [PATCH 05/22] ci: pin RaidHub-Services to 0e6bf77 for schema parity Fix ESLint no-unsafe-call on getInstancePlayerInfo in instances test (avoid .catch(console.error) widening types). Made-with: Cursor --- .github/raidhub-services-version.env | 2 +- src/services/player-instances/instances.test.ts | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/raidhub-services-version.env b/.github/raidhub-services-version.env index bc78fd49..416b2c97 100644 --- a/.github/raidhub-services-version.env +++ b/.github/raidhub-services-version.env @@ -1,2 +1,2 @@ RAIDHUB_SERVICES_REPO=Raid-Hub/RaidHub-Services -RAIDHUB_SERVICES_COMMIT=858b76cf0314c1d5547a60011bf444eb63615e88 +RAIDHUB_SERVICES_COMMIT=0e6bf77f6ee4e84c9d0adc6190358b918fdf3626 diff --git a/src/services/player-instances/instances.test.ts b/src/services/player-instances/instances.test.ts index 91a71e14..c44b1759 100644 --- a/src/services/player-instances/instances.test.ts +++ b/src/services/player-instances/instances.test.ts @@ -88,7 +88,7 @@ beforeAll(async () => { WHERE i.instance_id = $1::bigint`, [svcInstInstanceId] ) - const row = meta.rows[0]! + const row = meta.rows[0] fixtureActivityId = row.activityId fixtureVersionId = row.versionId fixtureSeason = row.season @@ -342,11 +342,17 @@ describe("getInstances", () => { }) test("whitelisted instance is not blacklisted", async () => { - const players = await getInstancePlayerInfo(svcInstInstanceId).catch(console.error) + let players: Awaited> + try { + players = await getInstancePlayerInfo(svcInstInstanceId) + } catch (err) { + console.error(err) + throw err + } expect(players).not.toBeNull() - expect(players!.length).toBeGreaterThan(0) + expect(players.length).toBeGreaterThan(0) - const membershipIds = players!.map(p => p.membershipId.toString()) + const membershipIds = players.map(p => p.membershipId.toString()) const data = await getInstances({ membershipIds, count: 100 From 777df855ee3008dd64fb195625c79732d640a867 Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 21:02:27 -0400 Subject: [PATCH 06/22] chore: refresh bun.lockb for Bun 1.3.13 (CI frozen install) Made-with: Cursor --- bun.lockb | Bin 325330 -> 324954 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bun.lockb b/bun.lockb index a07a944f3ce2e28a021dec65f33288860f39e54c..c1b89aeb3ad80ae5f8f47efc55c751506f091652 100755 GIT binary patch delta 58540 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�rOu6 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 delta 58447 zcmeFadz?;H|NnpOYh270Whyb{G;|;a<2VjuFq&=3xf7McV3@%;4KhkIbfTizvMAJa zM5%N_rRX4vqEu8W9Z`x7qEg@IYwvY+&$mza{k^}x-ygrnw2&CT<^Wkd+oKi zuI>E;r@VFWl-rs%+P!pP?c$ULXB^GlKWxQQb?T+~EL)i|;-@veyB?_! z(I;`RS4H#n66-mEWidM?8eu(%f zq`&KzIWC$pw6LHsFLn6PNG@@u7fs5YG`T3R=wAHQHiHf8 z8Zd0+8WZX)9uIf=L`@DP5CN$C)518f$yHa33FH72fs ze1!tlulHj4Q`$GEKuM(Z4jj}^y8tw%bZ?WepsiSCJTb3m+?XkOk#AEY5gK3mIaVY8 zE>;zdx4akrbZzOC%|gFx$yXKrYrfl?hsPD=7ZetjaK=`|@hlua;frADuoj`ibHvXi zp42iDVN6T!Bu+1uen~tTy9=ud#JhS5>HI0}XOElNI_&bs#Oc)17*_eePo|BrYq2Hj zirWdO>&9W_kYnxHmdCs9`}A;#5-i`tLGphbs|@F1Rl(7gcf~d$UdzV&bPOweghF-P z6;7liIJvrJge^Ls$)S^NQqh=#p^Wk5tgr<`u^PMHUBgM5)-4>!z2o>Lc$Cj>S6D@ zAhZMFD)@M>u)ya@uTQ)Tt69F>9zO<~LVOTbbD|qIXb4snI0LJmiegpK@%_SlN-id# zn!QFrn*GZ!4Cg}HMWN#otPcDdtJCe@b@^ABVZmkOqcJbVreJfhI*lh>8qS@fNfXCT zE{sH)z-d59=`0RZ!9QWu($<~AF+P7lcwiMA>%oVPyRt}^w^#5}4_ty(3y)kDw(tSs zb%~G1s>RK)n)TOQ5yq<%m;blqFa9RBF7vN+1p&>*;z8lq+(5hm@nP0>#i}J`L&BD2 z#>@I1L2%Nr5Q?R;+NJUpaOmy93Jp3 zP%Y@}gbPhutd`RIMuhSB#j)Nl42k ztMT7Xi`7FT$BY}AJEkZS#a}%!ZW{Bggg`$6I)~e0b-+nD=m4JzsEc=A9d_Bv*lNUw z<>!u}*CTVMhb{YeU3?n(X+GUYK00m`8!+ZxWDJGs+&{aN^DZcmKn=jfB*-?L5zgoz zIZ$2v4z?~fWoB5xCuvbF;!na=z>-Q~4;JT+8BrJnf7cIC&|(}*{p6}D_*-tcj1S>d>$ zbb2Jh)*vr+R8gd8wk-&&9xcu-Wco%T6Z1w)V(VO#d^0Up&5H8JO&&9xS$j)3=B==* zX(Jo2g_U15Y!z(c&0&RpyD5x+i&am(jg{ZCb3?uZzskgW-5NIVIh+28^*^`dwy?l0 z069KNT=plddSueXR&7+{{VYaIbgV*#YWahH%87MLE?5+%reQTu z^|9*U+woSl@8oD@|JReW>m6Y(lXA!B4jq#hNwC#FLbcUzyRkYI@}}gCWeXd5lDJB} zb4gh3`B-XO@+Y_-hoE3=H5{+So{SxX)l}|>RRy!|3Ri=s*y_aJ$EqJ{Vl|V7+#Ocn zr)A-y|1P#JyrIqSuClOV)$WNz8fw*OPeM%``rjL#6J4+>@LX%Z!BOW(BJujzGw@dn z6S1dYufIQx_hMjGk)kn^M;44Ij&!r}_SOy?Q#4f*VEn{_qC%$h_;H+K-SYE>k9ja0 z>9ts8*oXskj+~BFkDOrbPn;v_!V#Pkxx?}!j?MTU->Fu&WFM)j*2h>E%K|=n9L2pu zT-DluRez;D9Ol{(E5G<|{dD4*Z=;G*gOe+F;>hv2Ot~tSCs_X<9}17(hpmGDBaZ~N zKDjhLlU^AWR)4s^x>~c6OCAfeJrAo!Wj-Dr7QYK=57+!kc_Q?S-=%D`@wneQ;+nT@DVK{k)r(Eri@nPN4WZHjkOE$SH*9(ws3gs!0+>QAzy*tiJD(`27yTFInRa} z=N64kljnWJPa%V$V}s)&p7o2z%WQ?de=h8?p%ceV%;hG#)E1b>5%$6i8O>LY6Yx9fObQr6KrNl}LfFFLc|}2quh9eQ(zX7KlWVwJH-v|;@XJoF+vw27 zu-9h17`A3SR(TYT9$uiO;8_M)vucUI|Kw<6mOsE+|UXwJ~!4D`DzgmN(lJ9=(9L z`fTXLTm~r;`38S_1yMke)r{^pygrp9Cs4&_=*#MKCtk^@VKi;SM@K!o`vm>)ft(ArMj1u7K|Lr(ie%e0;pZ_ zeOP>2jVKs9JazK;Nb8To_ML0(_|!4uhUHG87GoHSNs)6u3DeIcpK9duteJ>j{esiZNlW6GQ=oG`3+oWSuEn=-Y+oi#EEt>j%dYS$ za=_nsT8)yqUxY^u{xWRhLs)f1Z>(yt6>n{iR%5k~`{Jwcn)4uWb*aJ1@9lkIKCfcc zRWtU7b`n-2eA0oiR@dO4OneBIeEmynBEz=0Wo`Of$Ew(;EiD@7vhIl7{so1N)=>`!RxIo17je0TAkbk8kGj6|}75@)o| zbYAi2r7L|m-fKJhxtC&Z`aXtruZ}Xe!}0v_W?gC!*d%lLh7}s zuR09z%Q8IYK7T*oU-)UAJm)mOnD0ycjh#Gq0rNlX;dyD9&Q`x~rkD5|tP{t_duaT0 z*Wa7zIXC!?I(yFZ{sg|i_1E!T&v&|bZXafh{2hO9dZshipV!56Hv7Bz{@qXM>LoU3 zVl*k2pL+ZXe|1;SS>PYzdz;@S%X8ZMv-vLZcVv0)r%aVrK?^kQr}??vJh%U;Rud9ljX854i{fGoFwP_LjSPWw#fGe0TYb2|6~_`cCE<9m(2KihLFao%+d za-T6E)4A9$_B`iSecj?3wKp`-gjav4=R-v;FmLvz){Jj9#8I&fmiKD}GXMI;C!S zS_G$0^n$wnJ-xG?hyDG%J?DErtq-%RURd97l=Js=pJ}3EQ>200)exrV#v&)~*&xCek>|!5MR;CMS^nXSOgEiaI6_I6W%}DM zuHf|W*Z0eE_V_z4_S}qfBasX74Off1{M<`C_d{4toW;&+%n14!mwK^*0qe50vp<7a zWu|hsAg9TGQh(1m>JRAexm{8tk$(793PyODzrR28sA(iJLbJsw@{0#(9ofkDkG^}E z=bqgx66uS7#7`^CbQb!HFY}y({$9SP`He33oR9nomwU0Z(;|@!e@~YzXPEC?;kk>6 z4-bx_h0bw*-W48e*KWQa^-~6V(IzeZQ3JD`tNqmjJ?9Vq*g!9K0llB$AAB~;ndQ$O zqy=QhATL_4wSW5HY|ho(!J73e277K=8)_Tm-S?YJ$N24rFe%zbB7*|9qhn?)kJu1D zV@Q^!Os?lPW=e-gkm}6y%W}P#(@wos^`R`cGofsb4dy}Y24X|}RfDsfFa3=}y=ag2 ze&u1=)TZw+FIuyMe+Q9k{Jq1x*ntk}wW`CioI(DC;a+SBr|JkD8H;8x1O1+PS<%Zg z{PXj&ofZDPJkOco@8rDN@Mm<&h{WFif z{*LjUTbp^W-U!Q|;O9>8+>J0Td|@vq(6q31%5gqHP5Q8PNBkKRy;u*<-7Ea1le_sz zMV@;;+5OoY&MLnQ_A5+_d@LBZwik!_M}zSwCZ;-uC;t|I<0LOy;}XB}_pD@LXCieHAnUbv&^hz(bfzIhIm)J=IB9RXM z`YBoNAVLgzI2W7;{FJF)w9;k%sHxepj`UleoML5!E>3hl&FH7*FPA{6+?s&E1q1{JxPQ0Jf`Ws^Jm zNmqNZ7K3^G8sxgzFC+fi5bm^t`dpN&hN$}Y64I29`AK6s`x~cwZV_Fg0S~&Ct9RdP zyx5t;B9UDAJCFH$i93v#7v$8PP=SAZYPSjm0+-myc|1}K5+@T14|~_2SL#KZj_}_v z&1OH8GQ)Ep84(U)qOK(Fxg#Ty=9J1cl#}@~VjA9Hb)g@+%=Da1{*IY7{KwifcYYz{ zxlK8*Sk$;;q;b_9?&n_1eh1bbRw3BG?ePy^>&4Ovw4!UBp6t)K&U050*GU-lbrt^A zPrBZ7TaOA)X!2scF7eB*_nbrieo`(U9f@?oyL#Zg#4oi1}Q4jwh?JMvLZt|Sj{_2}Nzw^x%Vl1_#N!lB` zbtgoEYiAhiM@+|82-?K5c(dmog#Fob(Q_vHzkHDG4&_|whGR@?C3E}mEmRh!Y3BGz z4`n9RDGD1LpUw&X-n6!^o<*vQiLs9C^ONR!(ez3FW!c%zb$;1g&wXxEc+yAx!|byM z`)Rj&&SJlq?>GI8w|dd+DSqYKvfZ33!|g@IU|4SS7vJVN>-@d9d5K3zVF~q`J?=7 zwsEU{&)s)bxFT}l@0aOzzB+7sCEu3dl=`z5=yJYeffqY{I^F8eS&)@<1)&zyE*hNT zkqGNvTHDw?&^~@f%Ph8Bhi~_y&9Cv>FU)o(`ZE@K?Ekkc^kS!!D2tx+v)s9af-Hg^ z#|FR5c+oDU{sEKCwmNN*$}C>w#WH4a`ufv5WyP)~)Jcar8~whEy=cdo{vC_uymzto z^NsHCSl1@p;klcy4bPi|VDx|YojbKZ&f)u@KkrVeb-n-oo!QPzKV^wF4+TrS*f}?- z6jiHGA+<~^Emy-XOTCzTBiAQ?>EbMBq`zaSZgi5D>1HH%nHTLm%U`)Hn=|V0GS4lW z9f_oIa7BN@)J*3sf5u&0{%#7pl(~FECU-kYcYD#ZZ}u;{J3Hypo9)eu?L|(`u5Dwt zLc99YZ^&{!@YBk?*oC*K-MWRE=Wi_YoV~t#j~A;uM_$~BCFT;+e2w4k==P+{-+Pbe z{Ny*fms5XkIL94Tz%3@GQzLBOtG;ue7pruuPO#(cvbforcc16pM_fMPR`p9i<$iLx zEj-B+f|*+6uZFFIh1V#Z_?6~`b1^}ub?ic7&CQP9(Np|G>CK&M{T&Z@&JI8MLC-zU z54$+QFS{+%y_uNKOV$hSd0z1k<56KjSmlUVwEF^o=JIUz1zVPTN$1`kiS)$Xc3Fg* zh3nfgmj|rSOqRR+;NP@1+wJ^7*z9oP-9{{fgHG~SFUw>bkh{*~mSn{`FV^ZohQ?1V%!*AT6s|e1 z`!k;LqNgwSUwbB-YjM)EUTo!ZwY=&*SzJlWo@HHG;U9Q5+Zo}fJ?FWbR>bE4w{LFp z%J>YT!=pV{`jyw~O3`<{=RQeNIG(zjKjQCQ@5P!w#M&72-;dS z3{R<=FEn>=B&z8VTy|L#=e@wL5!MYB?)`hNiVqZ5GWS|ynsC8I)p^!my}^t90c)=& zxa}SZdn4j^c_-7ILQKAizLS+n-a9sWv6CLv>aK0ZU_bXoFE-&ZDz3*2tdfUcWLgjp z^XD;2QmxgINHcPX*iUf!xfeiFp-koZna)%{>18kW7_6I`)ggG6^`l<~yx?)>aBwNP z*-v{#SIuI+oB4e=)$ng?-JCm8caz5g*>{uY)_pQ;v=glN!~DIQyx0@4HbG_g`x9RE z+;&gJcO`lvbFJ@e*3zG|nVsI#3{=>wWbArGH5~K<>;G&&Ws4Wv0qdsWaI3G0L@pqe z>;C*q_f=v#wSoKNUSZs75pTc zyT(s@gU1Wcg$p9rYU-X&ESxEt8&?z4#h4}I?aqGRH@W{>A1)%?wXjL+MXXIww!E(+ zrkYd;Hl{E76SjM?TFM!!UyzRx_A>KyUfA@rqVZZSJXH}+q9x<)6kzfaQv!A<@O&2W8 z4-b0#@J@E*FZ%7@(Pn4HJKP_<7*v4F>bw+p)!urDKj2-@S?!m->&3nyC0#QocIL|p zWgN?LuTY4>Sk!YeIdwL^=ea+WXNiqp3A?lWzIYr=T|kHPT=7wV?=CO)wfw^83!CCI zl8NTtL`+>8KKt72JMVjL#aF{2trQGFA7b4CkCYCb6N%{D4>!&4`6(ZG?n#^DW2nbx z+}nPj$12D8KHzux&~wk+5~f%1SHIXfk%)4ur0#R?Ag1gp29tiLpS#D4R(s7~xhLCs z$UnTtbANs<-T`S-c&6}r_;BzfT>w~|wtS?8HtAz_h+8#U>vOW)K7=&?x$LyebZ;T1 zkqNf^Y)R8T@!V?L;?2{X>S1HS&4xRRSm&U6q&Xk@efN59lQ+UrD+iSv?eB%HfHlW2 zysg>oPxzFb%A4i#r5~KnJoi=0f{U%2v^{Km7#l)NUC+LS1$ddC^0^n=2}=)#smhM9 zCe(|2`5wfyI>a<2Y&W}n;kjF^N0^)YR#%XTntmTe^z%c&(;r6z4y2l z!%t9^-Co4h#GrcILah5*54fCfc%HkR{Imun^(J&a89R~i6V>BbcQLdLG!oowz3K1x)^n?W7*6TnmNTh0 zF|XWltRd~&#_oo8{B!ANnjQX*g=`N`P=ZBju0P|D=e|W;ofTy6R{JQN$T4k$W8H`a zmrw4s$`11winx3$27h1kqo4M@=XU-$KA8F&muviuu;*Y}Pl8Fp6V<*yFl|4Hm!m;1 z^7q1Cf$1a)ZZlnHZ&)_l7cLyFiD~Lr(k_}lc79?(g(+Xh=c#@y@+moLC38Cwk}unW z^D}vvo^pi0TY{<6!VUdFfAtYB*5EUpzU&0u0fbtS>iW4WGTnv5dIi30W}MIc9Y6DQ z;Pdz?szqR`pL^6x+zeCs@!9cM8@Iw2dJx04GurzLzx}anZcSz!^W2?al^$L?D}Nb2 zhv%l`oy^#1Vx5Caz%zc?FPl*aF&kncmM9`>DV8hyNi@?K2mP%#BW#wGz`(gZ~XS>Wjhbv-o@cj zFIYXC=E{4Ql1jX`khMVUiN?se33KjNpFE8Dh$S(K`<5p2yi`(kgIF)5BCP%=k^S5fZKc zy{Q~?vYmmZZ;U)veIGs?3MOfJ$VO2Eq+`!S`joeoh&K*sXyw<$#${t>RReziBErHKeEyTw;VrG7Y-N;z z#92TBn~Bxu|H204|Lp;4UzZ@e&?XS>hE(8rmdn;f!)?60)$t>c{72gK|7p1b=%a)R zXf&#drXqc0l|iv0e9GIHsd|=E!_+# zLTiK6|J_zHwNJG5-(Zu=Tjl>U(&3wsKIN^_Ukm7ew(1u)XhAjKu>P{*Y=%mLgtu&h ztP0$T8X!*6ApNMd$FTaysshIq;UlYl_+1e`9hYM5nSy-ETcNY~l0BO*`8QI;T9wyW^G8#l1y*S-twVXM z1KYq=f%ev~gN|jaA0ou}aF}OUL)X>i9m^UWDaOq~u}?24LmL?`eVz23bDT z@;qzvEgyr`sW1Vn0*kQv$f}?#EibnADy;Iq#-`5L?mU4WTD!yAw{7}PtS(9)264uJ4*_NH304*P!p8Rn4w1-y ztTO!CrXRBDKiKpiZTb<*k73n-QaQJ_K~&Mb`Gm@+Wc` zUn=l&to#O9n~Rlyo{i^QI~vQMNTIdkusVLcjZd_85?1+L8Rh&}K>zQP9IwLaBdhav z23B1*3#%5-!RjJ$2Ub0H4^|a<0IQFzj(Zq;BK8@q@_p9wjaZfUGFJI*3Hm<>gb7=% z!<$%T{5Dnveq#A&mVbp+#lFRAMgGOc9dbXL_&Hb=bS_`=OT(%nEv#*cRRcPx|K-pX zs{`|~YQb2n3cd=fvA-Ux8sB8oZ^P;%OWBe6SotlnTviRZ8>@oLEH7_$T*J z%f@BZ1Mgzh(p{Fz>iFG3obyisIecIfJ`56AAj(-Cu!p$NCzk)6)zE!u)5}}szYl&A z_Gg8?bTt{9+yd&T6bHsCj>}s%Q)@TM?^*6S2zb1RJl4)kn5O;UvD~aH>s^ zRR-0qJl3bel_fjg~( ztPWgi2o#%SygPkjhDCbd%<#9`E9^fG)vQ%Qi^W2$$w{c_-mxA-rKC7 ztftO8Sf#&*RniB1X-0gah_woSZsW4@|I*rhno{}@_|vMOuZhckYk7IA3V#QeJ!I4W z&Z?mAt=|vUPgeOJ!7BY|g)F{J?RU&G8ma-CWhDf};NitEwbgzw)*QysqW4 z%CDY{%SKJlGq_(|(9)?EblREL=Paz;&efN-!PVNv)3C~`g^mB6RbRBS>Hmcd2ThJz zSa|LhbY>T=}w`thX#F0%F#Yx`s6KM2d8$S}S%I3uv~&$o6IR(|8L`izfJ zz8s4zC~tM(WXomcHx(;B&2m}Aug0pUuC-iN{x{h4Sy&D7e9LdgYV;PDScf~Y`jofI zV43CRt%l$(%Vkx8GOYMLSY`ZxO_xa=|ot713X^zv4Iui5n1ZMv-dw_;Vz?Ut9f>ZkWD$A&Yc90)4#Ar2bJPqAv> z7g%Ndr9Dtqe7}wVCo7k4`BH@sVU^EeYrl^T3ln~n7av(U{AA<*$tuI2@smAf{mWb3 zj6~H6Q`pw28{7+5P?XPqvI%B-UHhcMweJ6omFr1-osDg6kCRofgN@6owi#HpvXkY1 zV@Hu3I><589@xbm@c+arpRTsxESukX%FnDycWSg#a(A1(tl~LX4Ra40?}_D4$pHeTM!Z?a9Ff>nHK#qcyDKr8@Z2E{fmE61y_%J^!m zl4e?dog#c>b>iQGmERn!l6-yr#cIYcvVMz8ti$4RRt4TkT(>F9vC8-{n=Y#ip2Es+ z4OTt%j7=|ZRgq`mT2WrGelJ?TxIHT#kd@;mtTNtg9c82Dczvfvf%4mCli$QDu1|_p zJgmbTAf=xv$fvy36`^rJ|9S8|()PpuwEsN#4jznavfO7o=|5Rbw)@dP55DPye;$1Q z^WgiR2jBlZ`2Od?_dgH5|9S9T{sFkQ3I9C!F8@IMp9kOnJox4>dH;Fv9p141^WdAC zb)GP2q5S8;_dgH5^#J^z2jBlZ_zqWuzj@%zIuShY{^!AW_yAl_KmU2~{r{&2-}=8j z|MlQ|P2UdAne}@Nifu33vAu%Re%_&9Z+rcnd#88&dg_gX`@MSpy`%PRT+pLq;;Ho> zt#jn5j}IJrwaLX-w14EvdX1WIul@0`O><-2dNmz=3wb(`-%t7-JKPiubS^bD2RT*E zwt>zC&Ipq{2(VdT`XE5Q*&;A?Fd%g>V3a8y3}`q6ut#8wX*2||OJL3rz*w_eU{)?5 zBNs5<%+3X*4+R_)m}uG!1?&@8IutO;>=#%x4A65JV2W8h4A6Zz;JCn4lQSG}RAAL` zz%+AAV0j*3U>@LVvmy`Be*~cF2*5RFzz9I%NWgl5Qsa&UtQ9C637Bct3FPMkYUcy4 zGX?p8ngxJu0ymiC0>Ea0=>>pUW{beoQGnD@fSXM5C_ux}fIR}Ym`0-ky9DNp2Fx|P z1!j!_WQ+maW@e88q!$7X3d}d{3IY2BmKFjQnEe8a#sYed1uQg+#{#;K0~{AvWOBv< zjtZA;>IA?tGhhNBaUx*7z}?232v{pnI1zAu-t4Bm^vAdIvKFi6i)^;oC4S*@UUq#1+YtC z&J@5SX1BnsD*+i-0ve>I@$)qv;CfU5zC(*f%RHW+t0V68ym zbij*dok0FIfZEppUN!~S0BV*1wh3%9$t8fz0@F(Xo6Q!1silC_Qow7bxD?QE24IiC zR?}z(V3)w08Gtv;Zh=`d0U0v^+s*8mfb?qt2L;|T?XCsv6IgmJV5iwHu;@BK&+7p1 zn#I=vx?c}CF0jkwTn{)ZuRAS%6Q?I)VJzfZDSGpPPc&fSNY}wh4S`l5YZR7MOk$V4v9{F!g3Y>dk-y zrub$+!&?A*1imqiZUO8Pm~#u@TeDkW)*L{_9Kazndk!FdF5sZR_om%kz&?Sca{)h^ z{Q`?_1@ycXaKtRW70~@Qz;S`2Cg(Q5QGr#r0e&&Z1eVVO44en}&8(OQ=szD&bw1#C zGhjY|UyairfM~=qm3`+DvsR?g$0cgk`MBgS0MuRps9*{f0BYV2*d|cXB;O9$EHM3c zK%&_qFm)jybs?a#DP9O@XaIWzs+dLwuuEW$0i0-d3(Q&s$XEoZW@aw}q%Q^>6gb(m zTMXDIuyirtRI^`T(H(%EcK}W^i|+t*zY}m=pr*;W6L3^u)t!LT%`t)HO8^6x0BV^P zO91_s0;(;9OH&255K>V2?l()94<+E`d4s0GgWJ0<-P~WZVmAZf4&L zNWTwoP@sircOPJ%z|#8wt;~LbMfU@G-VbPF7T*u({s7>(K)T6!0B}@b)dPU`=9s|p z2LS^g1avej9t8AX4yd{u(8&x~4oF-9STE4oxGMl_1qxRHx|($Y`6~gnR|2}3f|Y=p z4*|9bWSiuN0GkD-KLqG*wg^mp7?Aof;Cxg3FreWoz#f4frqL?EE`d3#0KLp^fmx3L zG9Cf+F|!{5q(2HcDA3QedlaxwVCkcPi_Ct3MUMe`J_fkNEPf2oeKp{?K!2078gNu# z)oQ?H=9s|p#{mN$2V7xRJPzpp1fc2@fI()!6M)1g0qX^Z823rQT7kkR0Yl9?f&8Zc zwVwhEHw8}tYCa9vCNRPzKMmL{F#TyjzS$x$bqyeO4PcZhUIS>j7O+QPjA^tMuuEXh zTEJMdTVU2YK*l=2cr$w)ApIG@L4k>;-7|oF0!yC(Ofvfg7Cj5-`7B_HS^O-Z`*VQf z0#i-SbAY1)tDXZ)Gsgs$uLlfV54hT_SP$s`JfQ0HfNRWv=K+Z?0M-kX8utajT7kkB z05i=xf&2}C+8Y4ZnSu>~ni~Pz1a2_N8v&aIrf&qyGFt?uz6eNt5pa_!ei6{{CBPnm zTTG*u0J{X{yabqQb_>jU8IbWZ;5IY+WkC8XfP(__O}keB`vjK00$5=73oP0M=(!27 z&@A2r=>96;xWFQl^D5w|z^YdPcbH=W%QpiCZU!tdD>eiAZvj-@0$64SYyl*`23Rj} zw{c$stQ9DH4RDWHCy@U-p!Vy4`%J;>fSOwY+XNmk$y))N1*UHWEH_&OrfvhIZUd|| z#oGW4-vI0pc-S<01F%bA&KrP7%x-~MZvryj1UzPDzX?d+4mc?AxM{Z?uuov=cEFQn zzrdm$fSx-5Pn*R%0NvjL92Zz?a^3TC zA~1CqAaxhuHB-C`&~P_kkHA*bXg6S&z?|KHH_UEcf-Un1#e*icr@Rn)! z0brlN(hmST&3=JJ9|C%Q2zb{l{t(c858$}KE|aqda8zK`9>DwNn85On00Tb)d}vmD z1nB=Upz6nfkIaCN0g0ag)(d=M+)n^&1qwd_d}`JS-2$_|0AzdtIAmsj z0Z9K6a8TfT)9y>aK7plQ0)9061r~h;==l}kh*|sIXCL6Gz^Z+KU(7Lq z<@*5x_XB=2EA|8W9{^N60QlVuH~>ie8n7M^<$s5&{Ixb9B86Y$5;g0-#wGt7K<#e; z6->c5fSLyZ+XO0_42Bz#jp%%!(fY{eJ>f{RvRV4EPCjd(D2Gsr;aHc8v8Bp^mV4J|%Ciy5}v%vJDfQDv^z|>=a)MJ2iP4O{6!(RY<1e%ye zzW{a#%=rb-)a(|R^(!FbS3q+!`&U5vZ-9dWElj)L0Q&@%{sw4e_6saJ4(NFt(8er2 z4(R?n;J84#$@v{{RAANbfcEB?!16x;1OEVYG%NmaF1@{fwCe3uqijEJ9}uN89HQ%q zb~dg<_}>hv{xW%`+Rl}O%KiR7h~NWRGI z7g&@C=$Qz(#4Jt(baw&A1^SyD7jRTyl?%Ac91~bx88EOi;0m*%GNAtnfT|||2AKgT z01~SJ)(Z?VZWX{=77a8dU@A5|~pBFxKoAn3V*`NCJ#Evy%YnCj$-&Of>CI2J919 zdNN>=*)Oo@6hO~Y08`B3Qvlsh1soTcYI05m92Hn~Dqxy9Ca}CZU|@B?)n-L?K>yPK zRZjz4V+NcCNUQ-^FHmaS8i2I|g*5;(%{qbnnt<9h0oR#=nt+LF&jPG8#b*H;o()oU;LsnB4-i&H-ec19;5L zJ_nHA5O7f7anr6LV4uL!hJYu{et|`e06iN4o;Hgc0lJ?HI4-c(AM1{@Vw z)f(`=IVP~Y4Pam!z=vi<8$kcIfU0c)ADIDd0g35=^#Y$5HyyB6pfDZqsaYqG-wsf_ z9pH0Q&<;?uJz$%_mnOMAV6(vV_JDn6i@?+lfYc6v1E#nGpkYVA9)WL6qmF=G0&_Y7 zzBRiAW@P{}G609n>I{|()`vn$d0(xcwj+n)nfbN|E#|4g> zoX&uw0;@U$elf=cmUjUR>;m}Btmp#h-xW}`E8urCperCT3$Pv#jU<@LSy6T#B86GF zM9sP^T=KgCYIg%vFa_NJHO~WV6R2pC&*KVEY0ZT5qJKEf8^(M{77SKb4;wt?4o)`gU~9V};RAg6}J$f#YxeqlwYdOV@Oo5`8zy(Q6J} z9<7$(9AD!Mj`GhrT+aWd%m1!ks=xe*|08zO&A=hihhp2N@e9#4dnZI2ILgV5{}XZ7 zn~b5+U#ri&HvES|_(%PMfBQ!{6tC$yEZR02`+5#P4_d=({7!J(_`gc_l36+;dS&dH z1tjS`OBepxj@WMv`62ti>fbG>dDX()iKFv|Q^-oHs3Shs5tT>Te@!ZLRoEtfe0GyH z3&uw~J8t~nHTr$co(a*{okpj=6#PmlXk7fC7wQM&r{e*eJaP>Gtk$Ta``7F!ik=Zo z{_3^xUkFiC5_rDPPq<2(z0N-dqS6}&rH{A&6i}6|D*gSayZN24jJHfmarB8;on2H` zO=%f4VokNHqr0N9#IMyK!2p>)S41CPGiGMA?SlDfX_fcYNT9Gtq+W_yby`CElHdOb zKVqAxhyDgbzjW6p9#{2F4+uY4vOdbCmSvk^@~MFCw!a2=&HCvl2-jHlx@C%14p~V= zzmQj<`ro(XzYX7JnSRf(Jgjfz4a@Yaj)yJNuj+MdW%Q_J+hP0(eh&ATWp7zO{V(6~ z*FWf&`1+?_gC9@ard;^!w2tb5w*$g2D`ETzero-qW$#(PYQ&#KO5bH!5@8SNvm2(g zlTmj8J|9@WQwaCauS!(O4=p^Ea9^a)9?Pl|9vF~FEI_m8Qs!WQRmz;1)NqvIJHtCQ}Y5=Qc z*F3z``~c%m|DaPSa!^^#;`fC_*)#*o+c<2rr+uOYW-M3BcC9BezUA8;R6BTZ6DEQVP{|> zhb{cwI`TfX$PbqNVOg5laXOu*H$U+{tKg%zN2q+g<%xG$1t)gYvR1?&M4GM%mbE7Q z2-2s5Wo-yAMVgs0%i0nijWjbWT9!^YlL>|4WVTT6SGhGj(<6zNwTH!j^yk8;zTVy! zIl>5P7M@@k@1Bc%4bv>FYFP&1Z!9~>=BHOyeFoENR4sw>)naNA`P{-J>)07~H%!y@ zWXrk`ZVl7t6kAAF!fh<8ZvC=g>6V>lSvOca%e1Ph-1F4_4i?t5FdNpPZCSifO}huC8~S~eUu)Upg%@DhPM;1mlxS;rBu zxs0dAKhv_2gooKN?rd2;>;%iYSXKc0im*Oy&eNLas3*C*Suv4oe|f<4Q|!OAS_ZrOO)i7-_(2gaYs1oX86dVgFG0vgYW zNN*z10li?VbrCwnvfh?Wf~CTgNgvB56V_Wxlt*97`slRcv#6m;HHlU5@Mf4I{i`JoM&~s=#dfucqNT}glV9slhP&Zkpq=rwYSAV3lM?-hHnJ%xP z=Jo~&4N7z_>56zJIt%HNnS$!09Y{Y0eHp!i^o!CBNWVZ`fmR|dQ~@4C718DTG4K@x^sD3ks5{c{ox36ZZh8#|B%lt2JEBggEoy_> zqvz;2{f<{Z?$!G*e!=%w^cy;kv^n|%MM!s$_CZ`) znQ#`pf1a6rRzl-w-wNjGvl8m(Y{P2@(!S&g^dx!;twC$ieB`6s(L!X(M$Uz?TfVK*@v`8(>7VVV(o5ULHD7lNUz-bh6#5O_F~i*bwZ!O^xm=E zj=ACNgo!1G>Bb+>kLV|)D?(GGm0Vk(=4cbzf?h>0qgT+=XbpM+tw0ZgzP>=pCP?)>Lc_qx)79Q)P-mp~2eKD{f3^>kdzXbfo7s>Q5Vz|=?Crl^}T-D|1yPKjMdu* zve8$xPgmt<(Y@$CbU)HnSyy3Qb!Va3NLO23Ty-%WgmhudMY^mEpc~O_bQ8K6-Gb(z+t55TANgi)BlgmF5Y(%brXyV^N1~sp^HFpR={i{j)j%~- zGOCEaBu&@L2T&Qh2i2vMQc)A6w>REIU)+M`q8rdG)RR8wh58{+llM8=@Bn%cjY132 zbaV|WK{L=yq-$v@1t$38ihuqF{lvfja;?S>1ZFV)5Z52bP#=yendZ^6k1vzH9$Ts)a#43qF2$q=mB&t zYK+cAdOwujW%4Y(!OgKYVB3&xY_CL{NPG;PhB9%^M%=3fw_Mr7jZXQikhHiNE`BVkbeG!N6k+!jV z)5>?~3nV66hO~p6ho+$`&}7sHbwSzaVJg)b8*fD1#$ZvT&EXW3k5t*QdY9o?0(wWO z-cQ;cX>)fD>P8J!ur_u-pmAssDnM7GOHmJ`LYgA=+DMd#E<{t&vlMhS(q`@mJ*Ber z+ETqCW;|NknuPn2HgP8-ZQQg`Yl^fvQx`YGR!5t)+vk&bey};C>YR!o-Lh6d2}mzh z)NQ)1ae8*3=Nx({awpOQm^;v7q#-LnBT-W-q{gcgv|-Z5sTfT`+5&59JRA)}XQ5LO zgSMt^(}aR(iT0@4WNW)K0_CBzk#3;071j1~EYghBo>+TjZ9}zX)!w%alFuZhW3?@< zjIKmUNLN8EB-79hXg1P9qJ@QRUNo}C)J{t{gTKgVmzGesEfx2=#A)l zbRAlVl;zFnTBNyn6}lSf!aD=aM5Rc*thoHk7az|{RZ-r`m-LdLZZ;B!!GQ~KP$uyL z%V(yxl&_#Fq(yTMlAold`5-+@by27g9|H((k zmdNq1wbq8}QB*$DctL-csq*-1q5rM|;%kx3hj;T55mf8{nz@$zT28nyCSiXguAPPc zr}`?WGICKOs)S<5K^2g89(sVTdpzwne?`9|Ev~v6e1tyG;QvJ6NAxw?iuR$e(3j{7 z^f~$ry@x(U@1u9o4zwA)j^05V&@S{U`Vj3!pP-#+J9-o8vh@mj5xsz(*Z8lu+KAmy zE*=lRWZBE*(o|6uz5%H~`D{YUIG&$aJg&S|QSGTWAo<9ayk;YDAY0y1nTx%FHrTLi zJgi=bhu;Yd8GGmM=tUKil-9Se<^#OTD-OsT}>al1^c9osJA=$)Dp9ugC@x)ZIE|;!NkO z#y&nI>ek~Z-mPl6x;EZ>I#c4~td=TG6Fr`;3T!}s==@h9S~LXX87omdUfU??@e0I! z;)TcOLVOPCIH`Q=<34e|A?~B`uSn+c+Wrp*(*JZOT;5M(sh7%Y=;9Ss%hgM9Kehbt zDyCyp!IHRRykNDod{kzu0=Rx^75Fh6~|E33&SNwvd z9@3n%XHUtWYkc`aH{cNOVjZmE&=ADC|3bp$Z=SUmZcGoJgLHeT^m^FN*y`vk!e=7g zc8clNQ#afV^lvkqOQ0cYM1tTKA5!)5p1N0*@iD4xe?!ntS&8jO?=$Cm^L4-6wghRR$S>p<%i$s;@* zDbo>1ty4T7jYR5|0yGNg*a>JX(#`dFG!9L)R{UQLVEk1xb;V?)nyC==fHIOwk%nm+ znu^rIVss6fj;=;mA$pSXHx4-)?feTY6l>aq8c(#!iPU1{QfEvKY>W^&w% zGz^kj`X$l?)CB8>vQTHVA00sQ`4)YL4x`yfzHytt${9rtilE;~JC1%sOwy9buLOQU zSCjq+R^1uHu>w+edf4+&SJVY{M)go#q&ZLrTN~9vXP_$RbaV>R-#R3rYUo5%6;(!w zs1kDZJWB_hfVxlt{d*}X*qYcjSY>iDszP`I601S{G?YiUI`&i>j{9d2?}*x>MyMfb zg_M3Kwmu5xlB~vG1*Q>cfpkCvC0O2!a4Kqo&OypR{_%{@w(+yDDnM!SQ#c-POkDno zm-iPh5j>ZG5|l~&U}Y4~K2I7=IaM?h#VZ-ls~ao}X&AFL{y7A? zBNye6$puQlo{#ONxDEFquEj-bLT{xZ{Z+_iXaKqt>94)?*IyT+ey9(=mtgxNrCpA$ zKm(Ed`e^(|5XeKr&`{I@mWv&NIuKU8BN|Tp1sm7$sZRkcA1y)#=~8?n_69T#=>cjX z8iPh7RaTX{7CRG_%;0M(x)O~?Q&16_fF`2JXp)VWVy{BQHXiq%MqEBuqifJ~RD!NU z%1e1(kLID<(5+}LVudV;+(O_cG#kxAH={XdAzFauBOl$4K0$lXURv-W_D-Z8_yE0+ zcA~e@4zwL@L7UOj_^WqS0rk+U*iGmajsHsoUPK$w2BZb(Y3yU@QS=B}g&sx^A&uio zq?K$1_Aay>-H+}=OHoVGmSD@!z33ivHvTR>(F!PS)|#m3e>0IXRK{N_<6#*=;&heGGR4VVO@~KOVr}6=r!~@dJ}C! zZ=ko3x=R_W3l&yRsYlcs?;`br(%(V5(0gb%Qb8IX>0|T}+KY5${LI=zI{&{U@)i05 zsQ?`yrVM1`d_Q6J%vJbkPrr|FKKc$FMBgA)>T7fWsUaGFotk1}(YGj`r{>EcjsK4X zzDMzb;$y9`j2HAdVO8t{q$}PJSZe=g<>jYzHAH!-A*!I*&*%s`iqv|=WupmP@Kn3s z(XZ$@`VA>j5_fQlpg3P^)0F;;^{qrYbqdb!^z(H93(l{mVot)@YntaIJRd!M3CT(9 zWLwQYr{zsKZ!d{DgPJ#OnclQjTl4J&38y=&jN2ojrL)dt$h0sMdL;DZw_7hL*4+G{ zSO?RkXF@VRFS@*ELeJLvi@~a7_(iX8SG=`sZzSqmlh(9((^ip4XHrfi<>gsB-?;3@ z?a8FHAf-9$rP-q#t}s9MOc?2WX9o95NN)Xm#qfW3&X4_iSDXElAEIV0ac@Z`mBN&V zs@^>F#=Vy|Bc)YXL>;q=L(fRX;Z#bxd&e{5cbqtOu65u{=wkNbz|WX|?M2O(n4I32 z!Diz-38z+U-ZYJgYgYHh;gESu6N?tj@K@}Eb62+}z+SKk# zk9IbFWqO#0E&^U^?ouq@+rG z+TzXsoRIN>IVEV3ZLHRA6EFM=#B3ZEr~4x29lx(({WR)3!wPX1as@Lw6nNF#t*= z3RAHBNbCME!?ZqO?}Ty}{jES~G+$_Bt3Dx0qPPjJ_qm zzLK+RHo%!_ysl>Rhgs`2Pt>Xt@|!UDD^8iB9Pk%y15X7#=Z@)Q@9bi5injHIc4O%+ zFsObfhkl@}Keg{C`PB=nC49iHws5vM-wr90;_JIXZpHx{YwHF|afdAB^ z3cbDSrvaiP-oQhmhM;A}5a%|i^Nu4Sqq(`d+B-QKY^D#GOOp%$7ERXe`0(Z1i5EM_ z+J)3&sP8$+iaG^=qBsf(fPBP!IuK}bUNWaU0k|zSn^cj&!)|S|2^YFPHZK@eFi)*& z1i`a^r>Se8WU20ILvg{9g(kp8NU4ALUB{i9uML2IKurid20ZqeT6=I`0Tlj=TAF=n zc=v(PkXRrrh4mbz9ifON{Qoae*I|;STOlCp12}E{xPY#AUasP?fCFf4MbEyRN0qKj zj623P*o>j^v89&%LC!E4;>P5A-&I=qSARa1QDd-}!utdHP5?9p^4F>U5w~Mk+m@iX zDi1w%r$+PS_BXVAC^tB%9;E`gYyEmyQDE#3mnWKg4bnVg5IRSMQiJyBVI(h}GU~4p zJ1jy<#)eas0g&f1d1&MB{>VS6O>e}f<)TR@F95h*1^}b0;H#Y(7F7#wl>k)uTHro) zKcwiVTeSvp-0qB}#$VHd0bsftATT^?)B6^87pz021-e{$q8LjDfgJXDg%Pn|hPyHI z>dLG|gMQ&~TsSw#Caael>JDHfv(s_R$;IS2Cr|sY=PS>`)egOvW2b#5FgxS1S1J#0ghRB z9rdliuKD>9m;@qXoYrhW_5(3V7)^PI5H(<+WTiH;qse%utz(CNjJnw32bYSGg`K&{ zd)T|8lCz`4fs#(41KHT*2g#H^1WOe{*O#(LW7X+~g36=lVR6l9S<^B7t;W|V>G1`9 zaN;QS0f!d@+sw=^=^20?W*HF+{oS6leYw<_1!*pdqcm+0ME|M$baF7`a6lSbi1dn4;KwuE^{T!S?)a6q|!LTcasQe!PCj5ebRJX(lFB)e|Jp~b> za9~+bc5{`UqCOVnwEsqsmmp#UswmrIRjjtRn7YzfH53%EcvD(VB_b|I_zX??(od(g zgJEB%>1qg+a1)a-OL;XWFFVC$#T;hd!hgACSc-DZl)QeBD$wo#sU~?0k!q=h8Cl@l z%E%!=cAMt1CZ9G8L8u=`&xRnB3K+B6NG7G3Q>$9Sf?Hu;+5W;qBoEDbykqG)b8@pb z4;DL(dvyor!=d0Ftx-tpDd2bTC(P$Vh{$f>F!ud=KIb5T#M;g3Fzcv zAOmyjF{7wqlA#!AsiXoEXY2-H=*9E)HDbrQ+X>@fQMcToG&xkV(p<*=K4bq1&ZmG(m@mphKOTb~79K^9=D$!B zzMwT4fwe>Fn8#(p0&f}CtoV$GH;S={r!vBr5`FY-vwYd5mSDx#g+ysHi}(7Lvw zMGKIxeGm-lVqmKx46WdOKw=&#psF@dbbJ6ov(+B-3MCg{4 z^f-8te;nxQDML8aZr~A??l`Lic?3NMUHH+1GnfM(|4)xYbCf(sq4|e)EJE{wBJrfI z+M3P-m%2%7>aqfD`__~`3Q`XsrzwCMO&L?sL{YWT2*_(&V>=ZjU1;AozFO0tAM&Wg z3zC!M4FG&K9zPz1f!bS0T9dl3Ynxo}&08H*d-G?5`- z!EL-LEFJ^|(p82rj2^B)GoMVxpxH=uR-#F#$S5?Is6Tu8giK~&(yBgU(mcbYJ_VAg zK*@>w+J{;%1#iuL$a)^y&OUTw654(~^kgNb8bN6c-E?voi)Jl(u0oSaPuHNiL6Pj~ z1I}>y3+L$06~+E&W=N=BtNLl{HXSLtfi+=*YU_*vUJO5RAx+ONFHvXwQDOR zQ)R-Wf;Q)po0rTg=%yPBB^L!+=7rYGldL{NuOidN?Z}wPQXyF(VKsjJ5S8D&iNLJ% zl|4q0KUvShjDLS4YU8UDYCJr;)#5@4tqK--1_i6E{^G|V3YrXsO{6;0pfLSGI^|h0 z?_a3{vvOfU*b`tw)%s?lQ+z-+L1A=ig%^by*%D~#uO<3ZM#| zGEye{GiueBwnZ_`vWp2~ol7yQC{pn}Zmo)P6>>ke z+EV@5Qb)w&gR^0S56L?gdl2FYq*Lx}EQLU>aWszrzR@UKOPO;i8Wbi~k<@Mu;)NXk z<$$lJOC6d23`3POoPJJ_&9=12Wgume;^-+tBl*vTy@;ublZc!>^xaFblZA*J zr3|1rc*&tw4pA%|i8yFkim=bcH#uHI^eh^EY!C{mve{GWe97fA2~}pSH0_E$^yR22 z{9c54*Ko~Lr|gcrU})ySa*>`yiWwXfY_6*d*Km%0D^W9dP{+*K1OJ_gzOA>6|l3E$cKr1Ov%`wwarN_Yqa zN2Q|5QaItcP6^4y5|Y(a93Au{nj(r4M^eh1QV0~@KcgX8lKR}p5_QIp%>=B2A!!Ft z;4&n9&jC1*2UkU7s-@2fG^$imfd$ZFgi6#DThM6M0*)0a?vQ$S9Z0iq*2+bMSY@{Ydp15$^G9h z;XW#XAlMQMQbMr^%q(`Wh-{&?M!}Aq^r&Z}?k`Ume19ptMz&;+fpjev0j>K$irXMr zknw8CMLTnlC<*iSd|5-)VYoqw=4GvFRse#P!oe|~>fEA$J0%dZ?90~k{~JYdm@1V) ziZj!HU)O(>bV}#Q&uXJoe1Ly^6a}>9M}bnF{lAF@N)!-Irzw9?AP6oFgr$Y0SGbmn z#qv-&?u)|iV;?E@3bnrN>+l0~85Z74ne9re>b z^4^GI=O``Qi2CUw9cImSdbv>wQQHoq0h{2ox?y6k`1aMV$3h>~3M`q~cNi_*B$HVb3f>C(W+dY-MT7_lQiwxtJw+lDXSf=sfTo^F#&tvR~$ z;bPm_>ecW^n>yJ13}APhw_*3~I(6D2Sq^<616;W`A-wbUrtHMh(H#5>Zy zKsV?^&qUsX!PqrMPi;^zc2^&hw?(bjsa0lp!&Kc8E!(!AZ#1*;OxG^V7*HTFnRJez z^B_($1Q1Lm_f{?KGdQ3THvX_l&-oik(pIUlXOxWU;!uHdl0}O*p|iUWF;*!(BL@c! z8r?K>)Izg>pp?CR zYH@J(Re_4_#kLqr3ouqQ6%Z^@84O81@@P?HE+FJHj3sn%J6!2kx`IZt8*prQ%VqNX z6$O)b;F zXdDG5zyixODn7RMIEvbV(;dg1lA*fMINF*ZwNbYmM+FH|bNnV~(?pO)sVO-b2wv3Y6DctfCx7k}#UA)c^EYN+8a>Tccycu8h8}h% z)I4Qw_qS%jI~A0!2I2VWc(!*{E>9m*OyBOn#)f!fp|n~fjAbV`KAn4X?lgZ%s)F3f zRUTV`tpPaEX4cM7dwG*N8hkvN<_KWWBS%~vqdL35xGmh9MX`+Do6om@ z9*;VNc^l3I^k`A{m_{RZA#{XM-$U5oS+fhvNTVp)k9XSoQ9|smO$HBp?{a1(=5Rs? z!KsDabb0~^xAGty4Z?6AiS5o#c>2esD_;Athsw{iaNPeN+LCMoBDU2ubaJgbgVJ|{ zVp+lE8x=gK`X2}e`f8O;wA+u=51pFeAB7J;+%kAW+=ci(LKjS#Gic!-kT-t6^$*+= z>iCn0Ud}OtCLa7{%@noD3vXC7?v2(I?ZXy9K__(nm1QZpxit%;#(RKa0{QKMHia6s zGcX|wgW)UA8BLAuNXDw$K)^z%tO{-UqEk3=jHY*cKzw?%hzYrY2Byzq+DEHZJMe~? zY&JP0;S$GnJTlbp_Z&{icsY0lXk$U68SZq^lqAshf+z`zRW)aMGSpdRju`E*=K9fN z2mbEFS>Z-yCHJIR7jAtr+sl#n@YK_A4*4fb9o5a}&}!gNx0yqGk|mw1KSnV7+vky8 zWAdd&)A$IOAZ~P_he@E%(0^PGT}|JG9%pgf8BDcOK-4I5Pm%h2P6J#Gz0*pwuC|H+DAbLBui8Og+duGTjqELn57k{RlW;p!2zkcrqLonXU`qG zT`Qf6WW}B{Yz&G{puZ2GlzTx=sgkp{QjDk&R(ZI6`F``|_Z-fhMI=oOMWw?0>;Sx;e~-CzHqs0|Ix(f&655~6oc{Af znYQ4UnaT?yjs~$yg}xR93=cJI`FATegQyHaU8{qLtiMsOgV5V++HepTv5b}piY`|7 z7*WHl1FPFu%7!6Ypr;0CU2YuZ?HsV(57(jCwLzVu!8odhY@(e302Tvo=k2vhw=T-S zP@F(B6V^{VnyMsd%39;~!29OAetZsI8}e(6=7t!ujJykRO)Bk>R0~(Tt{%evsm%(C zIt8&ht)M1{(RNrtZ4YA&A&wB$KC5UuUgLMpj~zw;j-j`Qp{&@|f~aAhOQRz*b8(9a z%Hn}3mK=^isa&__)c=U&uC|Mz{6B#L_bgf03z~iud|AZf`XBgu-e_OSkjlw*d2V%L zXY2Oy%a4K(-*`$rhGCcK9N=+zq!SuV{8~}0B=`2nUb-JQWm!t*!vtQn@j6LU4Q`dzi()D^smfmqoeHjTWZZZgp{FLO3-ojw|5V!}p`^!qJ%xcAHJqj; z$W!-TPixq-!eyBgYRku`;8Di^hvF%oSC2DI`SZ;ruj4qM)yVGFDp0*Y>v1Iu&Gl zj;xtX0VkjVVTp$B`1*|&pMYhpqoXGzKXw=Oq~vV7W0P?1ds{^4e=$BF*=ls3)4D$rZIR%|Wo{_fF%VW+H(FFPJYQ|6U8fKgHj(NyLSu4*@cphc3WwcaI4~a*!kC#DPg3X8F!pNzFu}a; z-RW)B?9Gz_fB?rJ9@CG&;8p|xV*pIdKUA~trXscwM=!%rEm4HiPM7UG3_`E4brri0 zg&wOply_R{=w<~7#?`{N?dj?v225Rw3r2PO?_e`XVXAn(-$@VPnc^{;?XTg`(PNCHmzi*q=ZLAgi zj+2eWF~7%YT9K1cZ5LfWiuig2bQ?7ar>Z~b~W1i*)Q2+CAm&ha`EJ_J` z_Wk1f#-Ny8K7u%-(8EOW;lseQKI1#FdQa||OLem_`EnV+s>09FEe=;g)Vw2@`T=mLNFLy5*&QWu5Z=&fJ;Fw7idjam) zpE7dr#1Wd;hGNTM13G(7Pr;{{#gsZ^;)>J9m*|ryJ`-GuSJ+p9T5hKZnH{caT6IdD zs_e2JGh6V-=X1u7-~%PkSYjB%S_f;n^;y8gJDou&@G?TV7{arW(q!O_ECBQWw^TRS zN4eRs*m9|B}orvv`3KLasWk^6T!m_ZsK> zuEl3##j2Op#73py=lP5N0-+oc0#+(@yaX#2cq;&%cw<54m!z78kbwZCiGN97*|2?d z2&|o~wfb`k_PiaJ#RSIktwOyiIpjzc@Rv1Qb1)Itpe4=7K}hP6OmR72zf1#nW{VhE z(XsRp`qqq16XtR5X!i@-R-PIvYX%c>`EZroCXdUCLd}T_UNFNdjMJ2T8IJyhJg-Qd z)YZPCc~>xf#32#LzB%G)?myDM7e~uE6F2r=-<c7GHaowE7 zs(3QF3b<|LcNK6w$B6LXV?f@AH;aM_F%etmVWJKAgI91+hd=4~RcP)Vy~U%(=a>+c zVQ*dcGhb{z3V1o6EG36)*d*G9iCNT{{6#>l=e!Lg0Du6@lvd_c{DT?q<23aeT(`q< zT5%1rulsR2jc1MTFcC3JZI^DSp;3uVp40mjq0>+tmDbpJXQyhh8Y+YQ9_D2l%UG0ve()-0ilH=%iX zyAGE!!fzseN=k11usD9e=$k4oTy_o5;2xIOtnUAP&ZEKggY4Rsi19QXxCwH;86oQ> zGq2vnaN|AzkgrtFr7E|;dKvWM!YE@Mo4&1YVee~nn24v}t5#oW`!YTPDCFJfGIp|Y z`Jd&<<1`=0)iMgL**T$r=0i4*TGAkpIffgo1C!J}N4c0p+ZYfmXnXhfYG=45_Awyz z$@o`J)Yv@_{2O6ho?ALkF@M7ddYq>}(Ylr~gB+2{7r|U=dKzlP2E=V_HBk4Q*H+msi1hfHxrIX&YuzA|RAS zf?AhJw{J^2ZIAN;XKJ_5!|L~$i}-BZf?8#g?hdvCQfTEJT>hGOQK0_vey>_yYv#QH zpzIP=1GooN=Q$D#;@=zk?jP7|#Y|fF4~%&MJx0HFcZ^VX z?8&OL-7mmI2oA8PZ=As^O$ zlS5-!+cSqYqg73!tM@@;8TBahSWGdSOdfDIYmDYIM=5KlKLFG=mucby;BRu7wm*P2 z{4UdR_T2e0y~DHC=CUx%T_>i+_=Ifz8obC$bU->jgnyI|QL}-ld-|m1S6F@R5i9gq z@#2nei1~L6n&r6y`HA_HtJhR#qf~+CF@=c0c;9o%N^MSwfT~SBR z4PLrq|K$@{4Z*e9IS0N+d-Bg@ZTY?$3T=tqaI7Ks$*pI z1Tm|8-DXn26W|+tUl{(Dy1m!Enfaj}$H%2IofZQ?ZS;V)K7le}ZhthbKI zen@nPWZXLsQ_)k&uktMb7=zi_#NkbH#HQ0f+b1mUbu02ECUX|sDFQ&nhdI;f0$c&h zBGog9;{my{W*CLCW-R^kObRJO%E++1%I5B92?z3c4)8fNoYC3qiC}Vj?!LUbqncP@ zUO8rcJa0Kc0Vy882E+N*{Pa}p87xjZd^ps`DY}H=wPf-VViF9+VsL5{x&#GFB<_8i1(7PWDFa@3CdO+UO}K7$nR4 zF1RaOK>Z3~>U#Q6#nYxj$e}><3{eoCbcqDCPg&b@~3E2 zxcoKZlV_noRM@`xMxQe+=9M7&bc#S074T2s)^uqpim*-Jcb#K$XG>(sP(2!G_iJcc zyi#jl(Sz4g$1gX&l{l*Cchvfg)Rv;(NRHk%LqulyshR6()%fb~gXf6IFto@nV6JbC z`R#v}7xng?ANH?AYx?53Dx?&ja%88O$<6j5^!km|->Nj4;M1& From 335fa66a4e9f5b644ea8917154d62bc0fd1c0509 Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 21:05:24 -0400 Subject: [PATCH 07/22] style: prettier subscription/auth/pg files; fix unnecessary assertions in tests Made-with: Cursor --- src/auth/discord-context.ts | 1 - src/auth/express-auth-context.ts | 1 - src/auth/express-discord-context.ts | 1 - src/integrations/postgres/reader.ts | 2 +- src/integrations/postgres/transactional.ts | 2 +- src/routes/player/search.test.ts | 4 ++-- src/routes/player/search.ts | 3 ++- src/routes/subscriptions/discord/webhooks.ts | 5 ++--- .../components/DiscordSubscriptionWebhook.ts | 2 +- src/services/instance/instance.test.ts | 2 +- src/services/reporting/standing.test.ts | 6 +++--- src/services/search/player-search.test.ts | 4 ++-- .../subscriptions/discord-webhooks.test.ts | 10 ++-------- src/services/subscriptions/discord-webhooks.ts | 14 +++++++++----- 14 files changed, 26 insertions(+), 31 deletions(-) diff --git a/src/auth/discord-context.ts b/src/auth/discord-context.ts index cc7d636e..79be7b53 100644 --- a/src/auth/discord-context.ts +++ b/src/auth/discord-context.ts @@ -33,4 +33,3 @@ export const attachDiscordContext: RequestHandler = (req, res, next) => { }) } } - diff --git a/src/auth/express-auth-context.ts b/src/auth/express-auth-context.ts index 30620fc0..6061eb22 100644 --- a/src/auth/express-auth-context.ts +++ b/src/auth/express-auth-context.ts @@ -9,4 +9,3 @@ declare global { } export {} - diff --git a/src/auth/express-discord-context.ts b/src/auth/express-discord-context.ts index 33a66fc2..4ebfddeb 100644 --- a/src/auth/express-discord-context.ts +++ b/src/auth/express-discord-context.ts @@ -9,4 +9,3 @@ declare global { } export {} - diff --git a/src/integrations/postgres/reader.ts b/src/integrations/postgres/reader.ts index 32c46be0..b09705ea 100644 --- a/src/integrations/postgres/reader.ts +++ b/src/integrations/postgres/reader.ts @@ -5,7 +5,7 @@ export const readerMethods = (pool: Pool) => { return { async queryRow(sql: string, options: QueryOptions = {}): Promise { const rows = await executeQuery(pool, sql, "query_row", options) - return (rows[0]) || null + return rows[0] || null }, async queryRows(sql: string, options: QueryOptions = {}): Promise { diff --git a/src/integrations/postgres/transactional.ts b/src/integrations/postgres/transactional.ts index 46866f05..76148dfe 100644 --- a/src/integrations/postgres/transactional.ts +++ b/src/integrations/postgres/transactional.ts @@ -32,7 +32,7 @@ export function createTransactional(config: { const tx = { async queryRow(sql: string, options: QueryOptions = {}): Promise { const rows = await executeQuery(client, sql, "query_row", options) - return (rows[0]) || null + return rows[0] || null }, async queryRows(sql: string, options: QueryOptions = {}): Promise { return executeQuery(client, sql, "query_rows", options) diff --git a/src/routes/player/search.test.ts b/src/routes/player/search.test.ts index 0f014f48..1809deee 100644 --- a/src/routes/player/search.test.ts +++ b/src/routes/player/search.test.ts @@ -95,7 +95,7 @@ describe("player search 200", () => { if (data.type === "ok") { expect(data.parsed.results.length).toBeGreaterThan(0) - expect(data.parsed.results[0]!.membershipId).toBe(BigInt(searchFixtureMembershipId)) + expect(data.parsed.results[0].membershipId).toBe(BigInt(searchFixtureMembershipId)) } }) @@ -118,7 +118,7 @@ describe("player search 200", () => { if (data.type === "ok") { expect(data.parsed.results.length).toBeGreaterThan(0) - expect(data.parsed.results[0]!.membershipId).toBe(BigInt(searchFixtureMembershipId)) + expect(data.parsed.results[0].membershipId).toBe(BigInt(searchFixtureMembershipId)) } }) }) diff --git a/src/routes/player/search.ts b/src/routes/player/search.ts index e576db46..a623aa6e 100644 --- a/src/routes/player/search.ts +++ b/src/routes/player/search.ts @@ -14,7 +14,8 @@ Results are ordered by a combination of the number of raid completions and last query: z.object({ count: z.coerce.number().int().min(1).max(50).default(20), offset: z.coerce.number().int().min(0).max(5000).default(0).openapi({ - description: "Number of leading search hits to skip (for pagination). Must be 0 when count is the full result window." + description: + "Number of leading search hits to skip (for pagination). Must be 0 when count is the full result window." }), query: z.string().min(1).max(40), membershipType: zDestinyMembershipType.default(-1).openapi({ diff --git a/src/routes/subscriptions/discord/webhooks.ts b/src/routes/subscriptions/discord/webhooks.ts index 268a5fcf..93fe0726 100644 --- a/src/routes/subscriptions/discord/webhooks.ts +++ b/src/routes/subscriptions/discord/webhooks.ts @@ -1,11 +1,11 @@ import { RaidHubRoute } from "@/core/RaidHubRoute" -import { ErrorCode } from "@/schema/errors/ErrorCode" import { - zDiscordWebhookDeleteResponse, zDiscordWebhookBody, + zDiscordWebhookDeleteResponse, zDiscordWebhookPutResponse, zDiscordWebhookStatusResponse } from "@/schema/components/DiscordSubscriptionWebhook" +import { ErrorCode } from "@/schema/errors/ErrorCode" import { deleteDiscordWebhook, getDiscordWebhookStatus, @@ -95,4 +95,3 @@ export const getDiscordWebhookStatusRoute = new RaidHubRoute({ return RaidHubRoute.ok(await getDiscordWebhookStatus(req.discord.channelId)) } }) - diff --git a/src/schema/components/DiscordSubscriptionWebhook.ts b/src/schema/components/DiscordSubscriptionWebhook.ts index 91cedb3d..2e325194 100644 --- a/src/schema/components/DiscordSubscriptionWebhook.ts +++ b/src/schema/components/DiscordSubscriptionWebhook.ts @@ -1,5 +1,5 @@ -import { registry } from "@/schema/registry" import { zWholeNumber } from "@/schema/output" +import { registry } from "@/schema/registry" import { z } from "zod" export type DiscordWebhookBody = z.input diff --git a/src/services/instance/instance.test.ts b/src/services/instance/instance.test.ts index 01a2590b..2e98bd03 100644 --- a/src/services/instance/instance.test.ts +++ b/src/services/instance/instance.test.ts @@ -77,7 +77,7 @@ beforeAll(async () => { RETURNING hash::text AS "hash"`, [fixtureInstanceId] ) - fixtureHashForMetadata = ins.rows[0]!.hash + fixtureHashForMetadata = ins.rows[0].hash await fixtureDb.query( `INSERT INTO core.instance_player ( diff --git a/src/services/reporting/standing.test.ts b/src/services/reporting/standing.test.ts index 346944aa..603d1601 100644 --- a/src/services/reporting/standing.test.ts +++ b/src/services/reporting/standing.test.ts @@ -151,9 +151,9 @@ describe("getInstancePlayersStanding", () => { test("returns player standing with instance flags and no other-instance blacklist rows", async () => { const standing = await getInstancePlayersStanding(standingInstanceId) expect(standing.length).toBe(1) - expect(standing[0]!.playerInfo.membershipId).toBe(BigInt(standingMembershipId)) - expect(standing[0]!.flags.length).toBeGreaterThan(0) - expect(standing[0]!.blacklistedInstances.length).toBe(0) + expect(standing[0].playerInfo.membershipId).toBe(BigInt(standingMembershipId)) + expect(standing[0].flags.length).toBeGreaterThan(0) + expect(standing[0].blacklistedInstances.length).toBe(0) z.array(zInstancePlayerStanding).parse(standing) }) diff --git a/src/services/search/player-search.test.ts b/src/services/search/player-search.test.ts index 7d75a4be..7adc4edf 100644 --- a/src/services/search/player-search.test.ts +++ b/src/services/search/player-search.test.ts @@ -55,7 +55,7 @@ describe("searchForPlayer", () => { expect(parsed.error.errors).toEqual([]) } else { expect(parsed.data.results.length).toBeGreaterThan(0) - expect(parsed.data.results[0]!.membershipId).toBe(BigInt(svcSearchMembershipId)) + expect(parsed.data.results[0].membershipId).toBe(BigInt(svcSearchMembershipId)) expect(parsed.success).toBe(true) } }) @@ -79,7 +79,7 @@ describe("searchForPlayer", () => { expect(parsed.error.errors).toEqual([]) } else { expect(parsed.data.results.length).toBeGreaterThan(0) - expect(parsed.data.results[0]!.membershipId).toBe(BigInt(svcSearchMembershipId)) + expect(parsed.data.results[0].membershipId).toBe(BigInt(svcSearchMembershipId)) expect(parsed.success).toBe(true) } }) diff --git a/src/services/subscriptions/discord-webhooks.test.ts b/src/services/subscriptions/discord-webhooks.test.ts index dd24f751..08482e6e 100644 --- a/src/services/subscriptions/discord-webhooks.test.ts +++ b/src/services/subscriptions/discord-webhooks.test.ts @@ -74,10 +74,7 @@ describe("discord webhook subscriptions service", () => { } ]) queueQueryRows([[]]) - queueTransaction( - [{ destinationId: "99" }, { id: "99" }], - [[]] - ) + queueTransaction([{ destinationId: "99" }, { id: "99" }], [[]]) const result = await upsertDiscordWebhook({ guildId: "guild_1", @@ -115,10 +112,7 @@ describe("discord webhook subscriptions service", () => { } ]) queueQueryRows([[], []]) - queueTransaction( - [{ destinationId: "77" }, { id: "77" }], - [[]] - ) + queueTransaction([{ destinationId: "77" }, { id: "77" }], [[]]) const result = await upsertDiscordWebhook({ guildId: "guild_2", diff --git a/src/services/subscriptions/discord-webhooks.ts b/src/services/subscriptions/discord-webhooks.ts index 5ef505df..3d1f0da4 100644 --- a/src/services/subscriptions/discord-webhooks.ts +++ b/src/services/subscriptions/discord-webhooks.ts @@ -89,9 +89,7 @@ const createDiscordWebhook = async ( const defaultWebhookName = "RaidHub" const requestedName = body.name?.trim() const webhookName = - requestedName && requestedName.length > 0 - ? requestedName.slice(0, 80) - : defaultWebhookName + requestedName && requestedName.length > 0 ? requestedName.slice(0, 80) : defaultWebhookName const response = await fetch( `https://discord.com/api/v10/channels/${body.channelId}/webhooks`, @@ -536,7 +534,9 @@ export type DiscordWebhookStatusResult = }[] } -export async function getDiscordWebhookStatus(channelId: string): Promise { +export async function getDiscordWebhookStatus( + channelId: string +): Promise { logger.debug("DISCORD_WEBHOOK_STATUS_REQUESTED", { channelId }) const row = await pgAdmin.queryRow<{ destinationId: string @@ -572,7 +572,11 @@ export async function getDiscordWebhookStatus(channelId: string): Promise( + pgAdmin.queryRows<{ + membershipId: string + requireFresh: boolean + requireCompleted: boolean + }>( `SELECT membership_id::text AS "membershipId", require_fresh AS "requireFresh", From ef556ad325cd67d6ba4b73def4df0665458ba903 Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 21:08:22 -0400 Subject: [PATCH 08/22] fix: allow offset 0 in player search response schema; wire attachUserAuth in admin tests Made-with: Cursor --- src/auth/admin.test.ts | 5 ++++- src/routes/player/search.ts | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/auth/admin.test.ts b/src/auth/admin.test.ts index 9971d4ac..0f91be9f 100644 --- a/src/auth/admin.test.ts +++ b/src/auth/admin.test.ts @@ -3,10 +3,13 @@ import express from "express" import request from "supertest" import { adminProtected } from "./admin" import { generateJWT } from "./jwt" +import { attachUserAuth } from "./user-context" + +process.env.JWT_SECRET = process.env.JWT_SECRET || "test-secret" const app = express() -app.use("/admin", adminProtected, (req, res) => { +app.use("/admin", attachUserAuth, adminProtected, (req, res) => { res.status(200).json({ message: "Hello World" }) diff --git a/src/routes/player/search.ts b/src/routes/player/search.ts index a623aa6e..0ba26791 100644 --- a/src/routes/player/search.ts +++ b/src/routes/player/search.ts @@ -2,7 +2,7 @@ import { RaidHubRoute } from "@/core/RaidHubRoute" import { cacheControl } from "@/middleware/cache-control" import { zPlayerInfo } from "@/schema/components/PlayerInfo" import { zDestinyMembershipType } from "@/schema/enums/DestinyMembershipType" -import { zNaturalNumber } from "@/schema/output" +import { zNaturalNumber, zWholeNumber } from "@/schema/output" import { searchForPlayer } from "@/services/search/player-search" import { z } from "zod" @@ -34,7 +34,7 @@ Results are ordered by a combination of the number of raid completions and last .object({ params: z.object({ count: zNaturalNumber(), - offset: zNaturalNumber(), + offset: zWholeNumber(), query: z.string() }), results: z.array(zPlayerInfo) From fd0beb9f66fc1b593149811c6b8fa88cbde462e0 Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 21:09:23 -0400 Subject: [PATCH 09/22] docs: regenerate openapi.json (search offset schema) Made-with: Cursor --- open-api/openapi.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/open-api/openapi.json b/open-api/openapi.json index fd2b5986..c2e1cd52 100644 --- a/open-api/openapi.json +++ b/open-api/openapi.json @@ -2221,8 +2221,7 @@ }, "offset": { "type": "integer", - "minimum": 0, - "exclusiveMinimum": true + "minimum": 0 }, "query": { "type": "string" From 9572ceafb4b9f93bdfe4bbcb6d3a5c4786ade21f Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 21:13:12 -0400 Subject: [PATCH 10/22] fix: populate auth in RaidHubRoute.$mock from Bearer JWT (matches attachUserAuth) Made-with: Cursor --- src/auth/user-context.ts | 31 ++++++++++++++++++++----------- src/core/RaidHubRoute.ts | 5 ++++- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/auth/user-context.ts b/src/auth/user-context.ts index e620b075..b444cba6 100644 --- a/src/auth/user-context.ts +++ b/src/auth/user-context.ts @@ -1,6 +1,7 @@ import { RequestHandler } from "express" +import type { IncomingHttpHeaders } from "http" import jwt from "jsonwebtoken" -import { zJWTAuthFormat } from "./jwt" +import { zJWTAuthFormat, type JWTAuthContext } from "./jwt" const BEARER_AUTH_SCHEME = "Bearer" @@ -11,19 +12,27 @@ const extractBearerToken = (authorizationHeader?: string) => { return token || null } -export const attachUserAuth: RequestHandler = (req, _res, next) => { - const token = extractBearerToken(req.headers.authorization) - if (!token) { - req.auth = undefined - next() - return - } +const authorizationHeaderValue = (headers: IncomingHttpHeaders): string | undefined => { + const raw = headers.authorization + if (raw === undefined) return undefined + if (Array.isArray(raw)) return raw[0] + return raw +} + +/** Parse Bearer JWT into auth context (used by Express middleware and route $mock). */ +export const authFromHeaders = (headers: IncomingHttpHeaders): JWTAuthContext | undefined => { + const token = extractBearerToken(authorizationHeaderValue(headers)) + if (!token) return undefined try { const decoded = jwt.verify(token, process.env.JWT_SECRET) - req.auth = zJWTAuthFormat.parse(decoded) - } catch (error) { - req.auth = undefined + return zJWTAuthFormat.parse(decoded) + } catch { + return undefined } +} + +export const attachUserAuth: RequestHandler = (req, _res, next) => { + req.auth = authFromHeaders(req.headers) next() } diff --git a/src/core/RaidHubRoute.ts b/src/core/RaidHubRoute.ts index d5c8763a..25b05111 100644 --- a/src/core/RaidHubRoute.ts +++ b/src/core/RaidHubRoute.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any */ +import { authFromHeaders } from "@/auth/user-context" import { Logger } from "@/lib/utils/logging" import { durationMetrics } from "@/middleware/duration-metrics" import { regionMetrics } from "@/middleware/region-metrics" @@ -413,12 +414,14 @@ export class RaidHubRoute< } > { let after: () => Promise = () => Promise.resolve() + const headers = req.headers ?? {} const res = await this.handler( { params: this.paramsSchema?.parse(req.params) ?? {}, query: this.querySchema?.parse(req.query ?? {}) ?? {}, body: this.bodySchema?.parse(req.body) ?? {}, - headers: req.headers ?? {} + headers, + auth: authFromHeaders(headers) }, afterCallback => (after = afterCallback) ).then(this.buildResponse) From 5e95b56866d828c926b134256b7dcff4cf7fe5bf Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 21:18:11 -0400 Subject: [PATCH 11/22] test: cover authFromHeaders and more discord webhook service paths (CI coverage) Made-with: Cursor --- src/auth/user-context.test.ts | 69 +++++++++++++++++++ .../subscriptions/discord-webhooks.test.ts | 65 ++++++++++++++++- 2 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 src/auth/user-context.test.ts diff --git a/src/auth/user-context.test.ts b/src/auth/user-context.test.ts new file mode 100644 index 00000000..a60294e3 --- /dev/null +++ b/src/auth/user-context.test.ts @@ -0,0 +1,69 @@ +import { afterEach, describe, expect, test } from "bun:test" + +import { generateJWT } from "./jwt" +import { authFromHeaders } from "./user-context" + +describe("authFromHeaders", () => { + const origSecret = process.env.JWT_SECRET + + afterEach(() => { + process.env.JWT_SECRET = origSecret + }) + + test("returns undefined when Authorization is missing", () => { + expect(authFromHeaders({})).toBeUndefined() + }) + + test("returns undefined for non-Bearer scheme", () => { + expect( + authFromHeaders({ + authorization: "Basic abc" + }) + ).toBeUndefined() + }) + + test("returns undefined for invalid JWT", () => { + process.env.JWT_SECRET = "test-secret" + expect( + authFromHeaders({ + authorization: "Bearer not-a-jwt" + }) + ).toBeUndefined() + }) + + test("parses Bearer JWT into auth context", () => { + process.env.JWT_SECRET = "test-secret" + const token = generateJWT( + { + isAdmin: true, + bungieMembershipId: "999", + destinyMembershipIds: ["1", "2"] + }, + 600 + ) + const auth = authFromHeaders({ + authorization: `Bearer ${token}` + }) + expect(auth).toEqual({ + isAdmin: true, + bungieMembershipId: "999", + destinyMembershipIds: ["1", "2"] + }) + }) + + test("uses first header value when authorization is an array", () => { + process.env.JWT_SECRET = "test-secret" + const token = generateJWT( + { + isAdmin: false, + bungieMembershipId: "1", + destinyMembershipIds: [] + }, + 600 + ) + const auth = authFromHeaders({ + authorization: [`Bearer ${token}`, "ignored"] + }) + expect(auth?.bungieMembershipId).toBe("1") + }) +}) diff --git a/src/services/subscriptions/discord-webhooks.test.ts b/src/services/subscriptions/discord-webhooks.test.ts index 08482e6e..452f439f 100644 --- a/src/services/subscriptions/discord-webhooks.test.ts +++ b/src/services/subscriptions/discord-webhooks.test.ts @@ -1,12 +1,19 @@ import { afterAll, beforeEach, describe, expect, test } from "bun:test" import { pgAdmin } from "@/integrations/postgres" -import { getDiscordWebhookStatus, upsertDiscordWebhook } from "./discord-webhooks" +import { + deleteDiscordWebhook, + getDiscordWebhookStatus, + registerDiscordWebhook, + upsertDiscordWebhook +} from "./discord-webhooks" describe("discord webhook subscriptions service", () => { const originalQueryRow = pgAdmin.queryRow.bind(pgAdmin) const originalQueryRows = pgAdmin.queryRows.bind(pgAdmin) const originalTransaction = pgAdmin.transaction.bind(pgAdmin) + const originalFetch = globalThis.fetch + const originalBotToken = process.env.DISCORD_BOT_TOKEN const queueQueryRow = (values: unknown[]) => { const queue = [...values] @@ -51,12 +58,16 @@ describe("discord webhook subscriptions service", () => { pgAdmin.queryRow = originalQueryRow pgAdmin.queryRows = originalQueryRows pgAdmin.transaction = originalTransaction + globalThis.fetch = originalFetch + process.env.DISCORD_BOT_TOKEN = originalBotToken }) afterAll(() => { pgAdmin.queryRow = originalQueryRow pgAdmin.queryRows = originalQueryRows pgAdmin.transaction = originalTransaction + globalThis.fetch = originalFetch + process.env.DISCORD_BOT_TOKEN = originalBotToken }) test("upsertDiscordWebhook updates existing active destination", async () => { @@ -186,4 +197,56 @@ describe("discord webhook subscriptions service", () => { ] }) }) + + test("getDiscordWebhookStatus returns registered false when channel is unknown", async () => { + queueQueryRow([null]) + + const result = await getDiscordWebhookStatus("no_such_channel") + + expect(result).toEqual({ registered: false }) + }) + + test("deleteDiscordWebhook deactivates destination", async () => { + pgAdmin.transaction = (async callback => { + const tx = { + queryRow: async () => ({ destinationId: "55" }), + queryRows: async () => [] + } + return callback(tx as never) + }) as typeof pgAdmin.transaction + + await deleteDiscordWebhook("channel_to_delete") + }) + + test("registerDiscordWebhook throws when DISCORD_BOT_TOKEN is unset", () => { + delete process.env.DISCORD_BOT_TOKEN + + return expect( + registerDiscordWebhook({ + guildId: "g", + channelId: "c", + name: "Test", + filters: {}, + targets: {} + }) + ).rejects.toThrow("DISCORD_BOT_TOKEN") + }) + + test("registerDiscordWebhook throws when Discord returns error", () => { + process.env.DISCORD_BOT_TOKEN = "fake-token" + globalThis.fetch = async () => + new Response("rate limited", { + status: 429, + statusText: "Too Many Requests" + }) + + return expect( + registerDiscordWebhook({ + guildId: "g", + channelId: "c", + filters: {}, + targets: {} + }) + ).rejects.toThrow("Discord webhook create failed with status 429") + }) }) From aa6d512acf103d5e59b6cf027b82e931617686fe Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 21:20:44 -0400 Subject: [PATCH 12/22] test: fix user-context header array case typing for tsc Made-with: Cursor --- src/auth/user-context.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auth/user-context.test.ts b/src/auth/user-context.test.ts index a60294e3..a7181fa1 100644 --- a/src/auth/user-context.test.ts +++ b/src/auth/user-context.test.ts @@ -63,7 +63,7 @@ describe("authFromHeaders", () => { ) const auth = authFromHeaders({ authorization: [`Bearer ${token}`, "ignored"] - }) + } as unknown as Parameters[0]) expect(auth?.bungieMembershipId).toBe("1") }) }) From a09f2893f401dbe988613cbff4e30245da5dfa2a Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 21:23:25 -0400 Subject: [PATCH 13/22] test: registerDiscordWebhook happy path with mocked Discord API Made-with: Cursor --- .../subscriptions/discord-webhooks.test.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/services/subscriptions/discord-webhooks.test.ts b/src/services/subscriptions/discord-webhooks.test.ts index 452f439f..5f9ed614 100644 --- a/src/services/subscriptions/discord-webhooks.test.ts +++ b/src/services/subscriptions/discord-webhooks.test.ts @@ -249,4 +249,36 @@ describe("discord webhook subscriptions service", () => { }) ).rejects.toThrow("Discord webhook create failed with status 429") }) + + test("registerDiscordWebhook creates new destination when channel is new", async () => { + process.env.DISCORD_BOT_TOKEN = "fake-token" + globalThis.fetch = async () => + new Response(JSON.stringify({ id: "wh_new", token: "tok_new" }), { + status: 200, + headers: { "Content-Type": "application/json" } + }) + + queueTransaction([null, { id: "100" }], [[]]) + + const result = await registerDiscordWebhook({ + guildId: "guild_reg", + channelId: "chan_reg", + name: " CustomName ", + filters: { requireFresh: true, requireCompleted: false }, + targets: {} + }) + + expect(result).toEqual({ + guildId: "guild_reg", + channelId: "chan_reg", + webhookId: "wh_new", + webhookUrl: "https://discord.com/api/webhooks/wh_new/tok_new", + created: true, + activated: false, + rules: { + players: { inserted: 0, updated: 0 }, + clans: { inserted: 0, updated: 0 } + } + }) + }) }) From 54d610797ef87e824e8650a99cf50bb0360c06fd Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 21:26:15 -0400 Subject: [PATCH 14/22] test: upsertDiscordWebhook register branch for uncovered channel Made-with: Cursor --- .../subscriptions/discord-webhooks.test.ts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/services/subscriptions/discord-webhooks.test.ts b/src/services/subscriptions/discord-webhooks.test.ts index 5f9ed614..bedae2c6 100644 --- a/src/services/subscriptions/discord-webhooks.test.ts +++ b/src/services/subscriptions/discord-webhooks.test.ts @@ -250,6 +250,32 @@ describe("discord webhook subscriptions service", () => { ).rejects.toThrow("Discord webhook create failed with status 429") }) + test("upsertDiscordWebhook registers when channel has no destination yet", async () => { + process.env.DISCORD_BOT_TOKEN = "fake-token" + globalThis.fetch = async () => + new Response(JSON.stringify({ id: "wh_ups", token: "tok_ups" }), { + status: 200, + headers: { "Content-Type": "application/json" } + }) + + queueQueryRow([null]) + queueTransaction([null, { id: "200" }], [[]]) + + const result = await upsertDiscordWebhook({ + guildId: "guild_u", + channelId: "chan_u", + filters: {}, + targets: {} + }) + + expect(result.created).toBe(true) + expect(result.updated).toBe(false) + expect(result.activated).toBe(false) + expect(result.webhookId).toBe("wh_ups") + expect(result.webhookUrl).toBe("https://discord.com/api/webhooks/wh_ups/tok_ups") + expect(result.rules.players.inserted).toBe(0) + }) + test("registerDiscordWebhook creates new destination when channel is new", async () => { process.env.DISCORD_BOT_TOKEN = "fake-token" globalThis.fetch = async () => From 1428441f7fb03c11d6e8cbf68fe5de2048c6ec7a Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 23:46:21 -0400 Subject: [PATCH 15/22] fix: align Discord webhook auth contracts and rule reconciliation Address PR review feedback by registering InvalidDiscordAuthError, documenting 401 responses for Discord webhook routes, hardening Discord auth header parsing, adding API key path fallback, and reconciling/de-duping webhook targets with bounded input size. Made-with: Cursor --- src/auth/api-keys.ts | 3 +- src/auth/discord-context.test.ts | 52 +++++ src/auth/discord-context.ts | 18 +- src/routes/subscriptions/discord/webhooks.ts | 12 +- .../components/DiscordSubscriptionWebhook.ts | 12 +- src/schema/errors/InvalidDiscordAuthError.ts | 11 + .../subscriptions/discord-webhooks.test.ts | 26 +++ .../subscriptions/discord-webhooks.ts | 191 +++++++++++------- 8 files changed, 239 insertions(+), 86 deletions(-) create mode 100644 src/auth/discord-context.test.ts create mode 100644 src/schema/errors/InvalidDiscordAuthError.ts diff --git a/src/auth/api-keys.ts b/src/auth/api-keys.ts index 7220f799..ec28e3bf 100644 --- a/src/auth/api-keys.ts +++ b/src/auth/api-keys.ts @@ -12,7 +12,8 @@ const KeySchema = z.object({ key: z.string() }) -const apiKeys = file(process.env.API_KEYS_PATH, { type: "application/json" }) +const apiKeysPath = process.env.API_KEYS_PATH ?? "./api-keys.json" +const apiKeys = file(apiKeysPath, { type: "application/json" }) .json() .then( ( diff --git a/src/auth/discord-context.test.ts b/src/auth/discord-context.test.ts new file mode 100644 index 00000000..85990d0e --- /dev/null +++ b/src/auth/discord-context.test.ts @@ -0,0 +1,52 @@ +import { describe, expect, test } from "bun:test" +import { attachDiscordContext } from "./discord-context" + +describe("attachDiscordContext", () => { + test("ignores non-Discord authorization headers provided as arrays", () => { + let nextCalled = false + const req = { + headers: { + authorization: ["Bearer token"] + } + } as never + const res = {} as never + + attachDiscordContext(req, res, () => { + nextCalled = true + }) + + expect(nextCalled).toBe(true) + expect(req.discord).toBeUndefined() + }) + + test("returns InvalidDiscordAuthError for invalid Discord token in header array", () => { + let statusCode: number | undefined + let payload: unknown + const req = { + headers: { + authorization: ["Discord invalid-token"] + } + } as never + const res = { + status: (code: number) => { + statusCode = code + return { + json: (body: unknown) => { + payload = body + } + } + } + } as never + + attachDiscordContext(req, res, () => {}) + + expect(statusCode).toBe(401) + expect(payload).toMatchObject({ + success: false, + code: "InvalidDiscordAuthError", + error: { + message: "Invalid Discord context token" + } + }) + }) +}) diff --git a/src/auth/discord-context.ts b/src/auth/discord-context.ts index 79be7b53..2b2e19d1 100644 --- a/src/auth/discord-context.ts +++ b/src/auth/discord-context.ts @@ -1,18 +1,27 @@ import { verifyDiscordInvocationContext } from "@/integrations/discord/context-jwt" +import { InvalidDiscordAuthError } from "@/schema/errors/InvalidDiscordAuthError" import { ErrorCode } from "@/schema/errors/ErrorCode" import { RequestHandler } from "express" +import { IncomingHttpHeaders } from "http" const DISCORD_AUTH_SCHEME = "Discord" +const authorizationHeaderValue = (headers: IncomingHttpHeaders): string | undefined => { + const raw = headers.authorization + if (raw === undefined) return undefined + if (Array.isArray(raw)) return raw[0] + return raw +} + const extractDiscordContextToken = (authorizationHeader?: string) => { if (!authorizationHeader) return null - const [scheme, token] = authorizationHeader.trim().split(" ") + const [scheme, token] = authorizationHeader.trim().split(/\s+/, 2) if (scheme !== DISCORD_AUTH_SCHEME) return null return token || null } export const attachDiscordContext: RequestHandler = (req, res, next) => { - const token = extractDiscordContextToken(req.headers.authorization) + const token = extractDiscordContextToken(authorizationHeaderValue(req.headers)) if (!token) { req.discord = undefined next() @@ -23,13 +32,14 @@ export const attachDiscordContext: RequestHandler = (req, res, next) => { req.discord = verifyDiscordInvocationContext(token) next() } catch { - res.status(401).json({ + const err: InvalidDiscordAuthError = { minted: new Date(), success: false, code: ErrorCode.InvalidDiscordAuthError, error: { message: "Invalid Discord context token" } - }) + } + res.status(401).json(err) } } diff --git a/src/routes/subscriptions/discord/webhooks.ts b/src/routes/subscriptions/discord/webhooks.ts index 93fe0726..31b9a8a8 100644 --- a/src/routes/subscriptions/discord/webhooks.ts +++ b/src/routes/subscriptions/discord/webhooks.ts @@ -6,20 +6,24 @@ import { zDiscordWebhookStatusResponse } from "@/schema/components/DiscordSubscriptionWebhook" import { ErrorCode } from "@/schema/errors/ErrorCode" +import { zInsufficientPermissionsError } from "@/schema/errors/InsufficientPermissionsError" +import { zInvalidDiscordAuthError } from "@/schema/errors/InvalidDiscordAuthError" import { deleteDiscordWebhook, getDiscordWebhookStatus, upsertDiscordWebhook } from "@/services/subscriptions/discord-webhooks" -import { z } from "zod" const discordGuildChannelAuthErrors = [ + { + statusCode: 401 as const, + code: ErrorCode.InvalidDiscordAuthError, + schema: zInvalidDiscordAuthError.shape.error + }, { statusCode: 403 as const, code: ErrorCode.InsufficientPermissionsError, - schema: z.object({ - message: z.literal("Forbidden") - }) + schema: zInsufficientPermissionsError.shape.error } ] diff --git a/src/schema/components/DiscordSubscriptionWebhook.ts b/src/schema/components/DiscordSubscriptionWebhook.ts index 2e325194..fd731e7a 100644 --- a/src/schema/components/DiscordSubscriptionWebhook.ts +++ b/src/schema/components/DiscordSubscriptionWebhook.ts @@ -2,6 +2,8 @@ import { zWholeNumber } from "@/schema/output" import { registry } from "@/schema/registry" import { z } from "zod" +const MAX_DISCORD_WEBHOOK_TARGETS = 250 + export type DiscordWebhookBody = z.input export const zDiscordWebhookBody = registry.register( "DiscordWebhookBody", @@ -16,8 +18,14 @@ export const zDiscordWebhookBody = registry.register( .optional(), targets: z .object({ - playerMembershipIds: z.array(z.string().regex(/^\d+$/)).optional(), - clanGroupIds: z.array(z.string().regex(/^\d+$/)).optional() + playerMembershipIds: z + .array(z.string().regex(/^\d+$/)) + .max(MAX_DISCORD_WEBHOOK_TARGETS) + .optional(), + clanGroupIds: z + .array(z.string().regex(/^\d+$/)) + .max(MAX_DISCORD_WEBHOOK_TARGETS) + .optional() }) .optional() }) diff --git a/src/schema/errors/InvalidDiscordAuthError.ts b/src/schema/errors/InvalidDiscordAuthError.ts new file mode 100644 index 00000000..c3f5e112 --- /dev/null +++ b/src/schema/errors/InvalidDiscordAuthError.ts @@ -0,0 +1,11 @@ +import { registerError } from "@/core/RaidHubResponse" +import { z } from "zod" +import { ErrorCode } from "./ErrorCode" + +export type InvalidDiscordAuthError = z.input +export const zInvalidDiscordAuthError = registerError( + ErrorCode.InvalidDiscordAuthError, + z.object({ + message: z.literal("Invalid Discord context token") + }) +) diff --git a/src/services/subscriptions/discord-webhooks.test.ts b/src/services/subscriptions/discord-webhooks.test.ts index bedae2c6..ace01e5e 100644 --- a/src/services/subscriptions/discord-webhooks.test.ts +++ b/src/services/subscriptions/discord-webhooks.test.ts @@ -138,6 +138,32 @@ describe("discord webhook subscriptions service", () => { expect(result.webhookId).toBe("webhook_xyz") }) + test("upsertDiscordWebhook reconciles rules when explicit empty targets are provided", async () => { + queueQueryRow([ + { + destinationId: "99", + webhookId: "webhook_abc", + isActive: true + } + ]) + queueTransaction([{ destinationId: "99" }, { id: "99" }], [[], [], []]) + + const result = await upsertDiscordWebhook({ + guildId: "guild_1", + channelId: "123456789", + filters: {}, + targets: { + playerMembershipIds: [], + clanGroupIds: [] + } + }) + + expect(result.rules).toEqual({ + players: { inserted: 0, updated: 0 }, + clans: { inserted: 0, updated: 0 } + }) + }) + test("getDiscordWebhookStatus returns full player/clan rule DTOs", async () => { queueQueryRow([ { diff --git a/src/services/subscriptions/discord-webhooks.ts b/src/services/subscriptions/discord-webhooks.ts index 3d1f0da4..0e03ae97 100644 --- a/src/services/subscriptions/discord-webhooks.ts +++ b/src/services/subscriptions/discord-webhooks.ts @@ -131,6 +131,8 @@ const validateDiscordWebhookUrl = (raw: string) => { } const toBigIntString = (value: string) => BigInt(value).toString() +const normalizeTargetIds = (values?: string[]) => + values === undefined ? undefined : [...new Set(values.map(toBigIntString))] async function getDiscordDestinationIdByChannelId( db: Pick, @@ -155,82 +157,118 @@ async function upsertDiscordRules( options: { requireFresh: boolean requireCompleted: boolean - playerMembershipIds: string[] - clanGroupIds: string[] + playerMembershipIds?: string[] + clanGroupIds?: string[] } ) { const { requireFresh, requireCompleted, playerMembershipIds, clanGroupIds } = options - const playerInsertResults = await Promise.all( - playerMembershipIds.map(async membershipId => { - const insertedRows = await db.queryRows<{ rowCount: number }>( - `INSERT INTO subscriptions.rule (destination_id, scope, membership_id, require_fresh, require_completed) - SELECT $1::bigint, 'player', $2::bigint, $3, $4 - WHERE NOT EXISTS ( - SELECT 1 FROM subscriptions.rule r - WHERE r.destination_id = $1::bigint - AND r.scope = 'player' - AND r.membership_id = $2::bigint - AND r.is_active - ) - RETURNING 1 AS "rowCount"`, - { - params: [destinationId, membershipId, requireFresh, requireCompleted] - } - ) + const playerInsertResults: { inserted: number; updated: number }[] = [] + for (const membershipId of playerMembershipIds ?? []) { + const insertedRows = await db.queryRows<{ rowCount: number }>( + `INSERT INTO subscriptions.rule (destination_id, scope, membership_id, require_fresh, require_completed) + SELECT $1::bigint, 'player', $2::bigint, $3, $4 + WHERE NOT EXISTS ( + SELECT 1 FROM subscriptions.rule r + WHERE r.destination_id = $1::bigint + AND r.scope = 'player' + AND r.membership_id = $2::bigint + AND r.is_active + ) + RETURNING 1 AS "rowCount"`, + { + params: [destinationId, membershipId, requireFresh, requireCompleted] + } + ) - if (insertedRows.length > 0) return { inserted: 1, updated: 0 } - - await db.queryRows( - `UPDATE subscriptions.rule - SET require_fresh = $3, - require_completed = $4 - WHERE destination_id = $1::bigint - AND scope = 'player' - AND membership_id = $2::bigint - AND is_active`, - { - params: [destinationId, membershipId, requireFresh, requireCompleted] - } - ) - return { inserted: 0, updated: 1 } - }) - ) + if (insertedRows.length > 0) { + playerInsertResults.push({ inserted: 1, updated: 0 }) + continue + } - const clanInsertResults = await Promise.all( - clanGroupIds.map(async groupId => { - const insertedRows = await db.queryRows<{ rowCount: number }>( - `INSERT INTO subscriptions.rule (destination_id, scope, group_id, require_fresh, require_completed) - SELECT $1::bigint, 'clan', $2::bigint, $3, $4 - WHERE NOT EXISTS ( - SELECT 1 FROM subscriptions.rule r - WHERE r.destination_id = $1::bigint - AND r.scope = 'clan' - AND r.group_id = $2::bigint - AND r.is_active - ) - RETURNING 1 AS "rowCount"`, - { - params: [destinationId, groupId, requireFresh, requireCompleted] - } - ) + await db.queryRows( + `UPDATE subscriptions.rule + SET require_fresh = $3, + require_completed = $4 + WHERE destination_id = $1::bigint + AND scope = 'player' + AND membership_id = $2::bigint + AND is_active`, + { + params: [destinationId, membershipId, requireFresh, requireCompleted] + } + ) + playerInsertResults.push({ inserted: 0, updated: 1 }) + } - if (insertedRows.length > 0) return { inserted: 1, updated: 0 } - - await db.queryRows( - `UPDATE subscriptions.rule - SET require_fresh = $3, - require_completed = $4 - WHERE destination_id = $1::bigint - AND scope = 'clan' - AND group_id = $2::bigint - AND is_active`, - { - params: [destinationId, groupId, requireFresh, requireCompleted] - } - ) - return { inserted: 0, updated: 1 } - }) - ) + if (playerMembershipIds !== undefined) { + await db.queryRows( + `UPDATE subscriptions.rule + SET is_active = false, + updated_at = NOW() + WHERE destination_id = $1::bigint + AND scope = 'player' + AND is_active + AND ( + array_length($2::bigint[], 1) IS NULL + OR membership_id <> ALL($2::bigint[]) + )`, + { params: [destinationId, playerMembershipIds] } + ) + } + + const clanInsertResults: { inserted: number; updated: number }[] = [] + for (const groupId of clanGroupIds ?? []) { + const insertedRows = await db.queryRows<{ rowCount: number }>( + `INSERT INTO subscriptions.rule (destination_id, scope, group_id, require_fresh, require_completed) + SELECT $1::bigint, 'clan', $2::bigint, $3, $4 + WHERE NOT EXISTS ( + SELECT 1 FROM subscriptions.rule r + WHERE r.destination_id = $1::bigint + AND r.scope = 'clan' + AND r.group_id = $2::bigint + AND r.is_active + ) + RETURNING 1 AS "rowCount"`, + { + params: [destinationId, groupId, requireFresh, requireCompleted] + } + ) + + if (insertedRows.length > 0) { + clanInsertResults.push({ inserted: 1, updated: 0 }) + continue + } + + await db.queryRows( + `UPDATE subscriptions.rule + SET require_fresh = $3, + require_completed = $4 + WHERE destination_id = $1::bigint + AND scope = 'clan' + AND group_id = $2::bigint + AND is_active`, + { + params: [destinationId, groupId, requireFresh, requireCompleted] + } + ) + clanInsertResults.push({ inserted: 0, updated: 1 }) + } + + if (clanGroupIds !== undefined) { + await db.queryRows( + `UPDATE subscriptions.rule + SET is_active = false, + updated_at = NOW() + WHERE destination_id = $1::bigint + AND scope = 'clan' + AND is_active + AND ( + array_length($2::bigint[], 1) IS NULL + OR group_id <> ALL($2::bigint[]) + )`, + { params: [destinationId, clanGroupIds] } + ) + } return { players: { @@ -261,8 +299,8 @@ export async function registerDiscordWebhook( const webhookUrl = validateDiscordWebhookUrl(webhook.url) const requireFresh = input.filters?.requireFresh ?? false const requireCompleted = input.filters?.requireCompleted ?? false - const playerMembershipIds = (input.targets?.playerMembershipIds ?? []).map(toBigIntString) - const clanGroupIds = (input.targets?.clanGroupIds ?? []).map(toBigIntString) + const playerMembershipIds = normalizeTargetIds(input.targets?.playerMembershipIds) + const clanGroupIds = normalizeTargetIds(input.targets?.clanGroupIds) const { created, activated, rules } = await pgAdmin.transaction(async tx => { const existing = await tx.queryRow<{ id: string; isActive: boolean }>( @@ -282,7 +320,10 @@ export async function registerDiscordWebhook( if (!existing.isActive) { await tx.queryRows( `UPDATE subscriptions.destination - SET is_active = true, updated_at = NOW() + SET is_active = true, + updated_at = NOW(), + deactivated_at = NULL, + deactivation_reason = NULL WHERE id = $1::bigint`, { params: [existing.id] } ) @@ -363,8 +404,8 @@ export async function updateDiscordWebhook( }) const requireFresh = input.filters?.requireFresh ?? false const requireCompleted = input.filters?.requireCompleted ?? false - const playerMembershipIds = (input.targets?.playerMembershipIds ?? []).map(toBigIntString) - const clanGroupIds = (input.targets?.clanGroupIds ?? []).map(toBigIntString) + const playerMembershipIds = normalizeTargetIds(input.targets?.playerMembershipIds) + const clanGroupIds = normalizeTargetIds(input.targets?.clanGroupIds) const rules = await pgAdmin.transaction(async tx => { const destinationId = await getDiscordDestinationIdByChannelId(tx, channelId) From e1489f00a79ddf0059dd3fd274c50af98475737e Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 23:47:43 -0400 Subject: [PATCH 16/22] docs: regenerate openapi after webhook auth error updates Refresh generated OpenAPI output so docs/checks reflect the new Discord webhook error contracts and schema updates. Made-with: Cursor --- open-api/openapi.json | 193 ++++++++++++++++++++++++++++++------------ 1 file changed, 140 insertions(+), 53 deletions(-) diff --git a/open-api/openapi.json b/open-api/openapi.json index c2e1cd52..411eeb30 100644 --- a/open-api/openapi.json +++ b/open-api/openapi.json @@ -1800,14 +1800,16 @@ "items": { "type": "string", "pattern": "^\\d+$" - } + }, + "maxItems": 250 }, "clanGroupIds": { "type": "array", "items": { "type": "string", "pattern": "^\\d+$" - } + }, + "maxItems": 250 } } } @@ -1998,6 +2000,16 @@ } ] }, + "InvalidDiscordAuthError": { + "type": "object", + "properties": { + "message": { + "type": "string", + "enum": ["Invalid Discord context token"] + } + }, + "required": ["message"] + }, "ManifestResponse": { "type": "object", "properties": { @@ -8505,25 +8517,50 @@ "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "minted": { - "type": "string", - "format": "date-time" - }, - "success": { - "type": "boolean", - "enum": [false] - }, - "code": { - "type": "string", - "enum": ["ApiKeyError"] + "anyOf": [ + { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["InvalidDiscordAuthError"] + }, + "error": { + "$ref": "#/components/schemas/InvalidDiscordAuthError" + } + }, + "required": ["minted", "success", "code", "error"] }, - "error": { - "$ref": "#/components/schemas/ApiKeyError" + { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["ApiKeyError"] + }, + "error": { + "$ref": "#/components/schemas/ApiKeyError" + } + }, + "required": ["minted", "success", "code", "error"] } - }, - "required": ["minted", "success", "code", "error"] + ] } } } @@ -8731,25 +8768,50 @@ "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "minted": { - "type": "string", - "format": "date-time" - }, - "success": { - "type": "boolean", - "enum": [false] - }, - "code": { - "type": "string", - "enum": ["ApiKeyError"] + "anyOf": [ + { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["InvalidDiscordAuthError"] + }, + "error": { + "$ref": "#/components/schemas/InvalidDiscordAuthError" + } + }, + "required": ["minted", "success", "code", "error"] }, - "error": { - "$ref": "#/components/schemas/ApiKeyError" + { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["ApiKeyError"] + }, + "error": { + "$ref": "#/components/schemas/ApiKeyError" + } + }, + "required": ["minted", "success", "code", "error"] } - }, - "required": ["minted", "success", "code", "error"] + ] } } } @@ -8858,25 +8920,50 @@ "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "minted": { - "type": "string", - "format": "date-time" - }, - "success": { - "type": "boolean", - "enum": [false] - }, - "code": { - "type": "string", - "enum": ["ApiKeyError"] + "anyOf": [ + { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["InvalidDiscordAuthError"] + }, + "error": { + "$ref": "#/components/schemas/InvalidDiscordAuthError" + } + }, + "required": ["minted", "success", "code", "error"] }, - "error": { - "$ref": "#/components/schemas/ApiKeyError" + { + "type": "object", + "properties": { + "minted": { + "type": "string", + "format": "date-time" + }, + "success": { + "type": "boolean", + "enum": [false] + }, + "code": { + "type": "string", + "enum": ["ApiKeyError"] + }, + "error": { + "$ref": "#/components/schemas/ApiKeyError" + } + }, + "required": ["minted", "success", "code", "error"] } - }, - "required": ["minted", "success", "code", "error"] + ] } } } From cd39af8b8a5467e0af8c95d65884e6c3fd279cb0 Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 23:50:09 -0400 Subject: [PATCH 17/22] test: fix discord-context request typing in middleware test Use an explicit unknown-to-request cast in the mock request setup so tsc accepts the test harness while preserving the header-array coverage. Made-with: Cursor --- src/auth/discord-context.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/auth/discord-context.test.ts b/src/auth/discord-context.test.ts index 85990d0e..c9fa72d4 100644 --- a/src/auth/discord-context.test.ts +++ b/src/auth/discord-context.test.ts @@ -8,15 +8,15 @@ describe("attachDiscordContext", () => { headers: { authorization: ["Bearer token"] } - } as never - const res = {} as never + } as unknown as Parameters[0] + const res = {} as Parameters[1] attachDiscordContext(req, res, () => { nextCalled = true }) expect(nextCalled).toBe(true) - expect(req.discord).toBeUndefined() + expect((req as { discord?: unknown }).discord).toBeUndefined() }) test("returns InvalidDiscordAuthError for invalid Discord token in header array", () => { @@ -26,7 +26,7 @@ describe("attachDiscordContext", () => { headers: { authorization: ["Discord invalid-token"] } - } as never + } as unknown as Parameters[0] const res = { status: (code: number) => { statusCode = code @@ -36,7 +36,7 @@ describe("attachDiscordContext", () => { } } } - } as never + } as Parameters[1] attachDiscordContext(req, res, () => {}) From e7130999c112291ae43914ced5d7ce573af7cc9c Mon Sep 17 00:00:00 2001 From: owen Date: Wed, 22 Apr 2026 23:51:08 -0400 Subject: [PATCH 18/22] style: apply prettier formatting to discord auth middleware Match repository formatting expectations for discord-context middleware so the format check passes in CI. Made-with: Cursor --- src/auth/discord-context.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auth/discord-context.ts b/src/auth/discord-context.ts index 2b2e19d1..eb7d9f1e 100644 --- a/src/auth/discord-context.ts +++ b/src/auth/discord-context.ts @@ -1,6 +1,6 @@ import { verifyDiscordInvocationContext } from "@/integrations/discord/context-jwt" -import { InvalidDiscordAuthError } from "@/schema/errors/InvalidDiscordAuthError" import { ErrorCode } from "@/schema/errors/ErrorCode" +import { InvalidDiscordAuthError } from "@/schema/errors/InvalidDiscordAuthError" import { RequestHandler } from "express" import { IncomingHttpHeaders } from "http" From c146e5f6bed72072110fba4439cb176e16a00c32 Mon Sep 17 00:00:00 2001 From: owen Date: Thu, 23 Apr 2026 00:18:54 -0400 Subject: [PATCH 19/22] fix: address Sentry PR review for Discord webhook persistence Delete the Discord webhook if the Postgres transaction fails after create, since the API cannot run inside a DB transaction. Run destination reactivation and rule updates in a single transaction during upsert. Extract shared update path for reuse. Made-with: Cursor --- .../subscriptions/discord-webhooks.test.ts | 55 +++- .../subscriptions/discord-webhooks.ts | 296 +++++++++++------- 2 files changed, 226 insertions(+), 125 deletions(-) diff --git a/src/services/subscriptions/discord-webhooks.test.ts b/src/services/subscriptions/discord-webhooks.test.ts index ace01e5e..ceffbab7 100644 --- a/src/services/subscriptions/discord-webhooks.test.ts +++ b/src/services/subscriptions/discord-webhooks.test.ts @@ -76,15 +76,8 @@ describe("discord webhook subscriptions service", () => { destinationId: "99", webhookId: "webhook_abc", isActive: true - }, - { - destinationId: "99" - }, - { - id: "99" } ]) - queueQueryRows([[]]) queueTransaction([{ destinationId: "99" }, { id: "99" }], [[]]) const result = await upsertDiscordWebhook({ @@ -114,16 +107,9 @@ describe("discord webhook subscriptions service", () => { destinationId: "77", webhookId: "webhook_xyz", isActive: false - }, - { - destinationId: "77" - }, - { - id: "77" } ]) - queueQueryRows([[], []]) - queueTransaction([{ destinationId: "77" }, { id: "77" }], [[]]) + queueTransaction([{ destinationId: "77" }, { id: "77" }], [[], []]) const result = await upsertDiscordWebhook({ guildId: "guild_2", @@ -276,6 +262,45 @@ describe("discord webhook subscriptions service", () => { ).rejects.toThrow("Discord webhook create failed with status 429") }) + test("registerDiscordWebhook deletes Discord webhook when DB transaction fails", async () => { + process.env.DISCORD_BOT_TOKEN = "fake-token" + const requests: { method: string; url: string }[] = [] + globalThis.fetch = async (input, init) => { + const url = + typeof input === "string" + ? input + : input instanceof Request + ? input.url + : input.href + requests.push({ method: init?.method ?? "GET", url }) + if (init?.method === "DELETE") { + return new Response(null, { status: 204 }) + } + return new Response(JSON.stringify({ id: "wh_orphan", token: "tok_o" }), { + status: 200, + headers: { "Content-Type": "application/json" } + }) + } + + queueTransaction([], []) + + try { + await registerDiscordWebhook({ + guildId: "g", + channelId: "c", + filters: {}, + targets: {} + }) + expect.unreachable("registerDiscordWebhook should have thrown") + } catch (error: unknown) { + expect(error).toBeInstanceOf(Error) + expect((error as Error).message).toContain("Unexpected tx.queryRow call") + } + + expect(requests.map(r => r.method)).toEqual(["POST", "DELETE"]) + expect(requests[1].url).toBe("https://discord.com/api/v10/webhooks/wh_orphan") + }) + test("upsertDiscordWebhook registers when channel has no destination yet", async () => { process.env.DISCORD_BOT_TOKEN = "fake-token" globalThis.fetch = async () => diff --git a/src/services/subscriptions/discord-webhooks.ts b/src/services/subscriptions/discord-webhooks.ts index 0e03ae97..a1621324 100644 --- a/src/services/subscriptions/discord-webhooks.ts +++ b/src/services/subscriptions/discord-webhooks.ts @@ -118,6 +118,30 @@ const createDiscordWebhook = async ( } } +/** Best-effort cleanup when DB persistence fails after Discord accepted create. */ +const deleteDiscordWebhookApi = async (webhookId: string) => { + const token = process.env.DISCORD_BOT_TOKEN + if (!token) return + + const response = await fetch(`https://discord.com/api/v10/webhooks/${webhookId}`, { + method: "DELETE", + headers: { Authorization: `Bot ${token}` } + }) + + if (!response.ok && response.status !== 404) { + const detail = await response.text() + logger.warn( + "DISCORD_WEBHOOK_ORPHAN_CLEANUP_FAILED", + null, + { + webhookId, + status: response.status, + detail + } + ) + } +} + const validateDiscordWebhookUrl = (raw: string) => { const value = raw.trim() if (!value) throw new Error("webhookUrl is empty") @@ -282,6 +306,48 @@ async function upsertDiscordRules( } } +type PgWrite = Pick + +async function updateDiscordWebhookInDb( + tx: PgWrite, + channelId: string, + input: UpdateDiscordWebhookInput, + normalized: { + requireFresh: boolean + requireCompleted: boolean + playerMembershipIds?: string[] + clanGroupIds?: string[] + } +): Promise { + const { requireFresh, requireCompleted, playerMembershipIds, clanGroupIds } = normalized + const destinationId = await getDiscordDestinationIdByChannelId(tx, channelId) + const existing = await tx.queryRow<{ id: string }>( + `SELECT id::text AS "id" + FROM subscriptions.destination + WHERE id = $1::bigint + LIMIT 1`, + { params: [destinationId] } + ) + if (!existing) { + throw new Error(`Subscription destination ${destinationId} not found`) + } + + await tx.queryRows( + `UPDATE subscriptions.discord_destination_config + SET guild_id = $2, + updated_at = NOW() + WHERE destination_id = $1::bigint`, + { params: [destinationId, input.guildId] } + ) + + return upsertDiscordRules(tx, destinationId, { + requireFresh, + requireCompleted, + playerMembershipIds, + clanGroupIds + }) +} + export async function registerDiscordWebhook( input: RegisterDiscordWebhookInput ): Promise { @@ -292,57 +358,60 @@ export async function registerDiscordWebhook( playerTargets: input.targets?.playerMembershipIds?.length ?? 0, clanTargets: input.targets?.clanGroupIds?.length ?? 0 }) - const webhook = await createDiscordWebhook({ - channelId: input.channelId, - name: input.name - }) - const webhookUrl = validateDiscordWebhookUrl(webhook.url) - const requireFresh = input.filters?.requireFresh ?? false - const requireCompleted = input.filters?.requireCompleted ?? false - const playerMembershipIds = normalizeTargetIds(input.targets?.playerMembershipIds) - const clanGroupIds = normalizeTargetIds(input.targets?.clanGroupIds) - - const { created, activated, rules } = await pgAdmin.transaction(async tx => { - const existing = await tx.queryRow<{ id: string; isActive: boolean }>( - `SELECT d.id::text AS "id", d.is_active AS "isActive" + let createdWebhook: { id: string; token: string; url: string } | null = null + try { + createdWebhook = await createDiscordWebhook({ + channelId: input.channelId, + name: input.name + }) + const webhookUrl = validateDiscordWebhookUrl(createdWebhook.url) + const requireFresh = input.filters?.requireFresh ?? false + const requireCompleted = input.filters?.requireCompleted ?? false + const playerMembershipIds = normalizeTargetIds(input.targets?.playerMembershipIds) + const clanGroupIds = normalizeTargetIds(input.targets?.clanGroupIds) + + const { created, activated, rules } = await pgAdmin.transaction(async tx => { + const webhook = createdWebhook! + const existing = await tx.queryRow<{ id: string; isActive: boolean }>( + `SELECT d.id::text AS "id", d.is_active AS "isActive" FROM subscriptions.discord_destination_config c INNER JOIN subscriptions.destination d ON d.id = c.destination_id WHERE c.channel_id = $1 LIMIT 1`, - { params: [input.channelId] } - ) + { params: [input.channelId] } + ) - let destinationId: string - let created = false - let activated = false - if (existing) { - destinationId = existing.id - if (!existing.isActive) { - await tx.queryRows( - `UPDATE subscriptions.destination + let destinationId: string + let created = false + let activated = false + if (existing) { + destinationId = existing.id + if (!existing.isActive) { + await tx.queryRows( + `UPDATE subscriptions.destination SET is_active = true, updated_at = NOW(), deactivated_at = NULL, deactivation_reason = NULL WHERE id = $1::bigint`, - { params: [existing.id] } - ) - activated = true - } - } else { - const inserted = await tx.queryRow<{ id: string }>( - `INSERT INTO subscriptions.destination (channel_type) + { params: [existing.id] } + ) + activated = true + } + } else { + const inserted = await tx.queryRow<{ id: string }>( + `INSERT INTO subscriptions.destination (channel_type) VALUES ($1) RETURNING id::text AS "id"`, - { params: ["discord_webhook"] } - ) - if (!inserted) throw new Error("Failed to create subscription destination") - destinationId = inserted.id - created = true - } + { params: ["discord_webhook"] } + ) + if (!inserted) throw new Error("Failed to create subscription destination") + destinationId = inserted.id + created = true + } - await tx.queryRows( - `INSERT INTO subscriptions.discord_destination_config + await tx.queryRows( + `INSERT INTO subscriptions.discord_destination_config (destination_id, guild_id, channel_id, webhook_id, webhook_token, updated_at) VALUES ($1::bigint, $2, $3, $4, $5, NOW()) ON CONFLICT (destination_id) @@ -352,41 +421,49 @@ export async function registerDiscordWebhook( webhook_id = EXCLUDED.webhook_id, webhook_token = EXCLUDED.webhook_token, updated_at = NOW()`, - { - params: [destinationId, input.guildId, input.channelId, webhook.id, webhook.token] - } - ) + { + params: [destinationId, input.guildId, input.channelId, webhook.id, webhook.token] + } + ) - const rules = await upsertDiscordRules(tx, destinationId, { - requireFresh, - requireCompleted, - playerMembershipIds, - clanGroupIds - }) + const rules = await upsertDiscordRules(tx, destinationId, { + requireFresh, + requireCompleted, + playerMembershipIds, + clanGroupIds + }) - return { created, activated, rules } - }) + return { created, activated, rules } + }) - logger.info("DISCORD_WEBHOOK_REGISTER_COMPLETED", { - guildId: input.guildId, - channelId: input.channelId, - webhookId: webhook.id, - created, - activated, - playerRulesInserted: rules.players.inserted, - playerRulesUpdated: rules.players.updated, - clanRulesInserted: rules.clans.inserted, - clanRulesUpdated: rules.clans.updated - }) + const webhook = createdWebhook + + logger.info("DISCORD_WEBHOOK_REGISTER_COMPLETED", { + guildId: input.guildId, + channelId: input.channelId, + webhookId: webhook.id, + created, + activated, + playerRulesInserted: rules.players.inserted, + playerRulesUpdated: rules.players.updated, + clanRulesInserted: rules.clans.inserted, + clanRulesUpdated: rules.clans.updated + }) - return { - guildId: input.guildId, - channelId: input.channelId, - webhookId: webhook.id, - webhookUrl, - created, - activated, - rules + return { + guildId: input.guildId, + channelId: input.channelId, + webhookId: webhook.id, + webhookUrl, + created, + activated, + rules + } + } catch (error) { + if (createdWebhook !== null) { + await deleteDiscordWebhookApi(createdWebhook.id).catch(() => undefined) + } + throw error } } @@ -407,34 +484,14 @@ export async function updateDiscordWebhook( const playerMembershipIds = normalizeTargetIds(input.targets?.playerMembershipIds) const clanGroupIds = normalizeTargetIds(input.targets?.clanGroupIds) - const rules = await pgAdmin.transaction(async tx => { - const destinationId = await getDiscordDestinationIdByChannelId(tx, channelId) - const existing = await tx.queryRow<{ id: string }>( - `SELECT id::text AS "id" - FROM subscriptions.destination - WHERE id = $1::bigint - LIMIT 1`, - { params: [destinationId] } - ) - if (!existing) { - throw new Error(`Subscription destination ${destinationId} not found`) - } - - await tx.queryRows( - `UPDATE subscriptions.discord_destination_config - SET guild_id = $2, - updated_at = NOW() - WHERE destination_id = $1::bigint`, - { params: [destinationId, input.guildId] } - ) - - return upsertDiscordRules(tx, destinationId, { + const rules = await pgAdmin.transaction(async tx => + updateDiscordWebhookInDb(tx, channelId, input, { requireFresh, requireCompleted, playerMembershipIds, clanGroupIds }) - }) + ) logger.info("DISCORD_WEBHOOK_UPDATE_COMPLETED", { guildId: input.guildId, @@ -492,38 +549,57 @@ export async function upsertDiscordWebhook( } } - let activated = false - if (!existing.isActive) { - await pgAdmin.queryRows( - `UPDATE subscriptions.destination + const requireFresh = input.filters?.requireFresh ?? false + const requireCompleted = input.filters?.requireCompleted ?? false + const playerMembershipIds = normalizeTargetIds(input.targets?.playerMembershipIds) + const clanGroupIds = normalizeTargetIds(input.targets?.clanGroupIds) + + const { rules, activated } = await pgAdmin.transaction(async tx => { + let activatedInner = false + if (!existing.isActive) { + await tx.queryRows( + `UPDATE subscriptions.destination SET is_active = true, updated_at = NOW(), deactivated_at = NULL, deactivation_reason = NULL WHERE id = $1::bigint`, - { params: [existing.destinationId] } + { params: [existing.destinationId] } + ) + activatedInner = true + logger.info("DISCORD_WEBHOOK_REACTIVATED", { + destinationId: existing.destinationId, + channelId: input.channelId + }) + } + + const rulesInner = await updateDiscordWebhookInDb( + tx, + input.channelId, + { + guildId: input.guildId, + filters: input.filters, + targets: input.targets + }, + { + requireFresh, + requireCompleted, + playerMembershipIds, + clanGroupIds + } ) - activated = true - logger.info("DISCORD_WEBHOOK_REACTIVATED", { - destinationId: existing.destinationId, - channelId: input.channelId - }) - } - const upd = await updateDiscordWebhook(input.channelId, { - guildId: input.guildId, - filters: input.filters, - targets: input.targets + return { rules: rulesInner, activated: activatedInner } }) return { - guildId: upd.guildId, - channelId: upd.channelId, + guildId: input.guildId, + channelId: input.channelId, webhookId: existing.webhookId, created: false, activated, updated: true, - rules: upd.rules + rules } } From cc620492ec891505036294496a5a738020616d54 Mon Sep 17 00:00:00 2001 From: owen Date: Thu, 23 Apr 2026 00:20:11 -0400 Subject: [PATCH 20/22] style: prettier discord-webhooks after Sentry fixes Made-with: Cursor --- .../subscriptions/discord-webhooks.ts | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/services/subscriptions/discord-webhooks.ts b/src/services/subscriptions/discord-webhooks.ts index a1621324..f3351f58 100644 --- a/src/services/subscriptions/discord-webhooks.ts +++ b/src/services/subscriptions/discord-webhooks.ts @@ -130,15 +130,11 @@ const deleteDiscordWebhookApi = async (webhookId: string) => { if (!response.ok && response.status !== 404) { const detail = await response.text() - logger.warn( - "DISCORD_WEBHOOK_ORPHAN_CLEANUP_FAILED", - null, - { - webhookId, - status: response.status, - detail - } - ) + logger.warn("DISCORD_WEBHOOK_ORPHAN_CLEANUP_FAILED", null, { + webhookId, + status: response.status, + detail + }) } } @@ -422,7 +418,13 @@ export async function registerDiscordWebhook( webhook_token = EXCLUDED.webhook_token, updated_at = NOW()`, { - params: [destinationId, input.guildId, input.channelId, webhook.id, webhook.token] + params: [ + destinationId, + input.guildId, + input.channelId, + webhook.id, + webhook.token + ] } ) From 7b3fdb84db6b1248402fc811e1af0ab76c2f40e3 Mon Sep 17 00:00:00 2001 From: owen Date: Thu, 23 Apr 2026 00:23:15 -0400 Subject: [PATCH 21/22] test: cover updateDiscordWebhook and orphan DELETE failure path Made-with: Cursor --- .../subscriptions/discord-webhooks.test.ts | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/services/subscriptions/discord-webhooks.test.ts b/src/services/subscriptions/discord-webhooks.test.ts index ceffbab7..4799a9a0 100644 --- a/src/services/subscriptions/discord-webhooks.test.ts +++ b/src/services/subscriptions/discord-webhooks.test.ts @@ -5,6 +5,7 @@ import { deleteDiscordWebhook, getDiscordWebhookStatus, registerDiscordWebhook, + updateDiscordWebhook, upsertDiscordWebhook } from "./discord-webhooks" @@ -70,6 +71,26 @@ describe("discord webhook subscriptions service", () => { process.env.DISCORD_BOT_TOKEN = originalBotToken }) + test("updateDiscordWebhook updates guild and rules in one transaction", async () => { + queueTransaction([{ destinationId: "42" }, { id: "42" }], [[]]) + + const result = await updateDiscordWebhook("channel_x", { + guildId: "guild_x", + filters: { requireFresh: true, requireCompleted: false }, + targets: {} + }) + + expect(result).toEqual({ + guildId: "guild_x", + channelId: "channel_x", + updated: true, + rules: { + players: { inserted: 0, updated: 0 }, + clans: { inserted: 0, updated: 0 } + } + }) + }) + test("upsertDiscordWebhook updates existing active destination", async () => { queueQueryRow([ { @@ -301,6 +322,34 @@ describe("discord webhook subscriptions service", () => { expect(requests[1].url).toBe("https://discord.com/api/v10/webhooks/wh_orphan") }) + test("registerDiscordWebhook logs when orphan DELETE returns error", async () => { + process.env.DISCORD_BOT_TOKEN = "fake-token" + globalThis.fetch = async (input, init) => { + if (init?.method === "DELETE") { + return new Response("discord says no", { status: 500 }) + } + return new Response(JSON.stringify({ id: "wh_bad_del", token: "tok_bd" }), { + status: 200, + headers: { "Content-Type": "application/json" } + }) + } + + queueTransaction([], []) + + try { + await registerDiscordWebhook({ + guildId: "g", + channelId: "c", + filters: {}, + targets: {} + }) + expect.unreachable("registerDiscordWebhook should have thrown") + } catch (error: unknown) { + expect(error).toBeInstanceOf(Error) + expect((error as Error).message).toContain("Unexpected tx.queryRow call") + } + }) + test("upsertDiscordWebhook registers when channel has no destination yet", async () => { process.env.DISCORD_BOT_TOKEN = "fake-token" globalThis.fetch = async () => From e963b7bcd8214a1f33f0e2f1157289c332048cd9 Mon Sep 17 00:00:00 2001 From: owen Date: Thu, 23 Apr 2026 00:32:24 -0400 Subject: [PATCH 22/22] fix: delete prior Discord webhook before register replaces credentials Sentry follow-up: registerDiscordWebhook always created a new channel webhook but could leave the previous Discord webhook orphaned when a row already existed (e.g. direct service calls). Look up stored webhook_id, best-effort DELETE, then create and persist the new webhook. Tests cover the DELETE+POST sequence and queue an extra queryRow for prior-id lookups. Made-with: Cursor --- .../subscriptions/discord-webhooks.test.ts | 44 ++++++++++++++++++- .../subscriptions/discord-webhooks.ts | 18 ++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/services/subscriptions/discord-webhooks.test.ts b/src/services/subscriptions/discord-webhooks.test.ts index 4799a9a0..4ca70823 100644 --- a/src/services/subscriptions/discord-webhooks.test.ts +++ b/src/services/subscriptions/discord-webhooks.test.ts @@ -253,6 +253,7 @@ describe("discord webhook subscriptions service", () => { test("registerDiscordWebhook throws when DISCORD_BOT_TOKEN is unset", () => { delete process.env.DISCORD_BOT_TOKEN + queueQueryRow([null]) return expect( registerDiscordWebhook({ @@ -267,6 +268,7 @@ describe("discord webhook subscriptions service", () => { test("registerDiscordWebhook throws when Discord returns error", () => { process.env.DISCORD_BOT_TOKEN = "fake-token" + queueQueryRow([null]) globalThis.fetch = async () => new Response("rate limited", { status: 429, @@ -285,6 +287,7 @@ describe("discord webhook subscriptions service", () => { test("registerDiscordWebhook deletes Discord webhook when DB transaction fails", async () => { process.env.DISCORD_BOT_TOKEN = "fake-token" + queueQueryRow([null]) const requests: { method: string; url: string }[] = [] globalThis.fetch = async (input, init) => { const url = @@ -324,6 +327,7 @@ describe("discord webhook subscriptions service", () => { test("registerDiscordWebhook logs when orphan DELETE returns error", async () => { process.env.DISCORD_BOT_TOKEN = "fake-token" + queueQueryRow([null]) globalThis.fetch = async (input, init) => { if (init?.method === "DELETE") { return new Response("discord says no", { status: 500 }) @@ -358,7 +362,7 @@ describe("discord webhook subscriptions service", () => { headers: { "Content-Type": "application/json" } }) - queueQueryRow([null]) + queueQueryRow([null, null]) queueTransaction([null, { id: "200" }], [[]]) const result = await upsertDiscordWebhook({ @@ -376,6 +380,43 @@ describe("discord webhook subscriptions service", () => { expect(result.rules.players.inserted).toBe(0) }) + test("registerDiscordWebhook deletes prior Discord webhook before replacing stored credentials", async () => { + process.env.DISCORD_BOT_TOKEN = "fake-token" + queueQueryRow([{ webhookId: "wh_prior" }]) + const requests: { method: string; url: string }[] = [] + globalThis.fetch = async (input, init) => { + const url = + typeof input === "string" + ? input + : input instanceof Request + ? input.url + : input.href + requests.push({ method: init?.method ?? "GET", url }) + if (init?.method === "DELETE") { + return new Response(null, { status: 204 }) + } + return new Response(JSON.stringify({ id: "wh_next", token: "tok_next" }), { + status: 200, + headers: { "Content-Type": "application/json" } + }) + } + + queueTransaction([{ id: "5", isActive: true }], [[]]) + + const result = await registerDiscordWebhook({ + guildId: "guild_r", + channelId: "chan_r", + filters: {}, + targets: {} + }) + + expect(requests.map(r => r.method)).toEqual(["DELETE", "POST"]) + expect(requests[0].url).toBe("https://discord.com/api/v10/webhooks/wh_prior") + expect(result.webhookId).toBe("wh_next") + expect(result.created).toBe(false) + expect(result.activated).toBe(false) + }) + test("registerDiscordWebhook creates new destination when channel is new", async () => { process.env.DISCORD_BOT_TOKEN = "fake-token" globalThis.fetch = async () => @@ -384,6 +425,7 @@ describe("discord webhook subscriptions service", () => { headers: { "Content-Type": "application/json" } }) + queueQueryRow([null]) queueTransaction([null, { id: "100" }], [[]]) const result = await registerDiscordWebhook({ diff --git a/src/services/subscriptions/discord-webhooks.ts b/src/services/subscriptions/discord-webhooks.ts index f3351f58..72fb7e68 100644 --- a/src/services/subscriptions/discord-webhooks.ts +++ b/src/services/subscriptions/discord-webhooks.ts @@ -154,6 +154,19 @@ const toBigIntString = (value: string) => BigInt(value).toString() const normalizeTargetIds = (values?: string[]) => values === undefined ? undefined : [...new Set(values.map(toBigIntString))] +/** Prior Discord webhook id for this channel, if any (used before replacing on re-register). */ +async function getExistingDiscordWebhookIdForChannel(channelId: string): Promise { + const row = await pgAdmin.queryRow<{ webhookId: string | null }>( + `SELECT webhook_id::text AS "webhookId" + FROM subscriptions.discord_destination_config + WHERE channel_id = $1 + LIMIT 1`, + { params: [channelId] } + ) + const id = row?.webhookId + return id && id.length > 0 ? id : null +} + async function getDiscordDestinationIdByChannelId( db: Pick, channelId: string @@ -356,6 +369,11 @@ export async function registerDiscordWebhook( }) let createdWebhook: { id: string; token: string; url: string } | null = null try { + const priorWebhookId = await getExistingDiscordWebhookIdForChannel(input.channelId) + if (priorWebhookId) { + await deleteDiscordWebhookApi(priorWebhookId) + } + createdWebhook = await createDiscordWebhook({ channelId: input.channelId, name: input.name