diff --git a/.github/workflows/backend-ci.yml b/.github/workflows/backend-ci.yml index 47b77718..7c5fd774 100644 --- a/.github/workflows/backend-ci.yml +++ b/.github/workflows/backend-ci.yml @@ -39,3 +39,15 @@ jobs: - name: Build run: pnpm --filter backend run build + + - name: Export OpenAPI spec + working-directory: app/backend + env: + DATABASE_URL: file:./prisma/dev.db + NODE_ENV: development + run: npm run spec:export + + - name: Check for OpenAPI spec drift + run: | + git diff --exit-code app/frontend/openapi.json || \ + (echo "ERROR: openapi.json is out of date. Run 'npm run spec:export' in app/backend and commit app/frontend/openapi.json." && exit 1) diff --git a/.gitignore b/.gitignore index 73726178..d9b2868e 100644 --- a/.gitignore +++ b/.gitignore @@ -153,3 +153,6 @@ GEMINI.md # Local planning/spec docs (not committed) docs/superpowers/ +plan.md +.playwright-mcp/ +dump.rdb \ No newline at end of file diff --git a/app/backend/package-lock.json b/app/backend/package-lock.json index 68763cbe..b9c0f13f 100644 --- a/app/backend/package-lock.json +++ b/app/backend/package-lock.json @@ -39,7 +39,8 @@ "pino-pretty": "^13.1.3", "prom-client": "^15.1.3", "reflect-metadata": "^0.2.2", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "twilio": "^6.0.2" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", @@ -2524,7 +2525,7 @@ }, "node_modules/@prisma/config": { "version": "6.19.2", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "c12": "3.1.0", @@ -2535,12 +2536,12 @@ }, "node_modules/@prisma/debug": { "version": "6.19.2", - "devOptional": true, + "dev": true, "license": "Apache-2.0" }, "node_modules/@prisma/engines": { "version": "6.19.2", - "devOptional": true, + "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -2552,12 +2553,12 @@ }, "node_modules/@prisma/engines-version": { "version": "7.1.1-3.c2990dca591cba766e3b7ef5d9e8a84796e47ab7", - "devOptional": true, + "dev": true, "license": "Apache-2.0" }, "node_modules/@prisma/fetch-engine": { "version": "6.19.2", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "@prisma/debug": "6.19.2", @@ -2567,7 +2568,7 @@ }, "node_modules/@prisma/get-platform": { "version": "6.19.2", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "dependencies": { "@prisma/debug": "6.19.2" @@ -2601,7 +2602,7 @@ }, "node_modules/@standard-schema/spec": { "version": "1.1.0", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@stellar/js-xdr": { @@ -2845,17 +2846,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/ioredis-mock": { - "version": "8.2.7", - "resolved": "https://registry.npmjs.org/@types/ioredis-mock/-/ioredis-mock-8.2.7.tgz", - "integrity": "sha512-YsGiaOIYBKeVvu/7GYziAD8qX3LJem5LK00d5PKykzsQJMLysAqXA61AkNuYWCekYl64tbMTqVOMF4SYoCPbQg==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "ioredis": ">=5" - } - }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "dev": true, @@ -3716,6 +3706,18 @@ "node": ">=0.4.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ajv": { "version": "6.14.0", "dev": true, @@ -4232,6 +4234,12 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, "node_modules/buffer-from": { "version": "1.1.2", "license": "MIT" @@ -4308,7 +4316,7 @@ }, "node_modules/c12": { "version": "3.1.0", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "chokidar": "^4.0.3", @@ -4335,7 +4343,7 @@ }, "node_modules/c12/node_modules/dotenv": { "version": "16.6.1", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -4460,7 +4468,7 @@ }, "node_modules/chokidar": { "version": "4.0.3", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "readdirp": "^4.0.1" @@ -4496,7 +4504,7 @@ }, "node_modules/citty": { "version": "0.1.6", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "consola": "^3.2.3" @@ -4709,7 +4717,7 @@ }, "node_modules/confbox": { "version": "0.2.4", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/consola": { @@ -4860,6 +4868,12 @@ "node": "*" } }, + "node_modules/dayjs": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", + "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.3", "license": "MIT", @@ -4903,7 +4917,7 @@ }, "node_modules/deepmerge-ts": { "version": "7.1.5", - "devOptional": true, + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=16.0.0" @@ -4939,7 +4953,7 @@ }, "node_modules/defu": { "version": "6.1.4", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/delayed-stream": { @@ -4965,7 +4979,7 @@ }, "node_modules/destr": { "version": "2.0.5", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/detect-libc": { @@ -5051,13 +5065,22 @@ "dev": true, "license": "MIT" }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "license": "MIT" }, "node_modules/effect": { "version": "3.18.4", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", @@ -5086,7 +5109,7 @@ }, "node_modules/empathic": { "version": "2.0.0", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -5524,12 +5547,12 @@ }, "node_modules/exsolve": { "version": "1.0.8", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/fast-check": { "version": "3.23.2", - "devOptional": true, + "dev": true, "funding": [ { "type": "individual", @@ -5550,7 +5573,7 @@ }, "node_modules/fast-check/node_modules/pure-rand": { "version": "6.1.0", - "devOptional": true, + "dev": true, "funding": [ { "type": "individual", @@ -6009,7 +6032,7 @@ }, "node_modules/giget": { "version": "2.0.0", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "citty": "^0.1.6", @@ -6228,6 +6251,19 @@ "url": "https://opencollective.com/express" } }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/human-signals": { "version": "2.1.0", "dev": true, @@ -7292,7 +7328,7 @@ }, "node_modules/jiti": { "version": "2.6.1", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -7378,6 +7414,49 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "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": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "dev": true, @@ -7466,10 +7545,46 @@ "version": "4.2.0", "license": "MIT" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, "node_modules/lodash.isarguments": { "version": "3.1.0", "license": "MIT" }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "dev": true, @@ -7480,6 +7595,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, "node_modules/log-symbols": { "version": "4.1.0", "dev": true, @@ -7820,7 +7941,7 @@ }, "node_modules/node-fetch-native": { "version": "1.6.7", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/node-gyp-build-optional-packages": { @@ -7867,7 +7988,7 @@ }, "node_modules/nypm": { "version": "0.6.5", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "citty": "^0.2.0", @@ -7883,7 +8004,7 @@ }, "node_modules/nypm/node_modules/citty": { "version": "0.2.1", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/object-assign": { @@ -7905,7 +8026,7 @@ }, "node_modules/ohash": { "version": "2.0.11", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/on-exit-leak-free": { @@ -8146,12 +8267,12 @@ }, "node_modules/pathe": { "version": "2.0.3", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/perfect-debounce": { "version": "1.0.0", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/picocolors": { @@ -8312,7 +8433,7 @@ }, "node_modules/pkg-types": { "version": "2.3.0", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "confbox": "^0.2.2", @@ -8396,7 +8517,7 @@ }, "node_modules/prisma": { "version": "6.19.2", - "devOptional": true, + "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -8539,7 +8660,7 @@ }, "node_modules/rc9": { "version": "2.1.2", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "defu": "^6.1.4", @@ -8565,7 +8686,7 @@ }, "node_modules/readdirp": { "version": "4.1.2", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 14.18.0" @@ -8738,6 +8859,13 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/scmp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz", + "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q==", + "deprecated": "Just use Node.js's crypto.timingSafeEqual()", + "license": "BSD-3-Clause" + }, "node_modules/secure-json-parse": { "version": "4.1.0", "funding": [ @@ -9420,7 +9548,7 @@ }, "node_modules/tinyexec": { "version": "1.0.4", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -9707,6 +9835,24 @@ "version": "2.7.0", "license": "0BSD" }, + "node_modules/twilio": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/twilio/-/twilio-6.0.2.tgz", + "integrity": "sha512-RN3TZxUtxLz2HBZVt62+LdZxQbrMVgYKtuzLgwmO7nqKvR+gQS5mCackD9hf4Y7MmoK/bX7tCm7kaJC8kC8zFA==", + "license": "MIT", + "dependencies": { + "axios": "^1.13.5", + "dayjs": "^1.11.9", + "https-proxy-agent": "^5.0.0", + "jsonwebtoken": "^9.0.3", + "qs": "^6.14.1", + "scmp": "^2.1.0", + "xmlbuilder": "^13.0.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/type-check": { "version": "0.4.0", "dev": true, @@ -9768,7 +9914,7 @@ }, "node_modules/typescript": { "version": "5.9.3", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -10272,6 +10418,15 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/xmlbuilder": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", + "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==", + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, "node_modules/y18n": { "version": "5.0.8", "dev": true, diff --git a/app/backend/package.json b/app/backend/package.json index b98768b7..b0ead11b 100644 --- a/app/backend/package.json +++ b/app/backend/package.json @@ -26,7 +26,8 @@ "test:cov": "jest --coverage", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", "test:e2e": "jest --config ./test/jest-e2e.json", - "test:e2e:ci": "prisma migrate deploy && jest --config ./test/jest-e2e.json --runInBand" + "test:e2e:ci": "prisma migrate deploy && jest --config ./test/jest-e2e.json --runInBand", + "spec:export": "ts-node --transpile-only -r tsconfig-paths/register scripts/export-spec.ts" }, "dependencies": { "@liaoliaots/nestjs-redis": "^10.0.0", diff --git a/app/backend/scripts/export-spec.ts b/app/backend/scripts/export-spec.ts new file mode 100644 index 00000000..9f94247c --- /dev/null +++ b/app/backend/scripts/export-spec.ts @@ -0,0 +1,47 @@ +/** + * Standalone OpenAPI spec export script. + * + * Boots the NestJS application context (no HTTP listener), generates the + * Swagger document, and writes it to app/frontend/openapi.json. + * + * Usage: + * cd app/backend + * DATABASE_URL=file:./prisma/dev.db npm run spec:export + * + * The output file is committed to source control so the frontend can run + * `pnpm generate:api` without a running backend, and CI can diff it to + * detect contract drift. + */ + +import { NestFactory } from '@nestjs/core'; +import { VersioningType } from '@nestjs/common'; +import { SwaggerModule } from '@nestjs/swagger'; +import { writeFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { AppModule } from '../src/app.module'; +import { buildSwaggerConfig } from '../src/swagger.config'; + +async function exportSpec() { + // abortOnError: false lets infrastructure providers (Redis, BullMQ) fail + // to connect without aborting the process. Swagger generation only reads + // decorator metadata so it succeeds regardless of connection state. + const app = await NestFactory.create(AppModule, { logger: false, abortOnError: false }); + + app.setGlobalPrefix('api'); + app.enableVersioning({ + type: VersioningType.URI, + defaultVersion: '1', + prefix: 'v', + }); + + const document = SwaggerModule.createDocument(app, buildSwaggerConfig()); + + const outPath = join(__dirname, '..', '..', 'frontend', 'openapi.json'); + writeFileSync(outPath, JSON.stringify(document, null, 2)); + + await app.close(); + + console.log(`✅ OpenAPI spec written to ${outPath}`); +} + +void exportSpec(); diff --git a/app/backend/src/campaigns/dto/create-campaign.dto.ts b/app/backend/src/campaigns/dto/create-campaign.dto.ts index 810183e2..95c41a79 100644 --- a/app/backend/src/campaigns/dto/create-campaign.dto.ts +++ b/app/backend/src/campaigns/dto/create-campaign.dto.ts @@ -34,6 +34,8 @@ export class CreateCampaignDto { description: 'Arbitrary campaign metadata (e.g., region, location, target audience).', example: { region: 'Lagos', partner: 'NGO-A', notes: 'Phase 1' }, + type: 'object', + additionalProperties: true, }) @IsOptional() @IsObject() diff --git a/app/backend/src/campaigns/dto/update-campaign.dto.ts b/app/backend/src/campaigns/dto/update-campaign.dto.ts index 607e97e2..15112a68 100644 --- a/app/backend/src/campaigns/dto/update-campaign.dto.ts +++ b/app/backend/src/campaigns/dto/update-campaign.dto.ts @@ -35,6 +35,8 @@ export class UpdateCampaignDto { @ApiPropertyOptional({ description: 'Updated campaign metadata.', example: { region: 'Lagos', partner: 'NGO-B' }, + type: 'object', + additionalProperties: true, }) @IsOptional() @IsObject() diff --git a/app/backend/src/common/hmac/hmac.service.ts b/app/backend/src/common/hmac/hmac.service.ts index 3926369c..53f690c7 100644 --- a/app/backend/src/common/hmac/hmac.service.ts +++ b/app/backend/src/common/hmac/hmac.service.ts @@ -4,10 +4,17 @@ import { createHmac, timingSafeEqual } from 'node:crypto'; @Injectable() export class HmacService { - private readonly secret: string; + private readonly secret: string | undefined; constructor(private readonly config: ConfigService) { - this.secret = this.config.getOrThrow('WEBHOOK_SECRET'); + this.secret = this.config.get('WEBHOOK_SECRET'); + } + + private getSecret(): string { + if (!this.secret) { + throw new Error('WEBHOOK_SECRET is not configured'); + } + return this.secret; } /** @@ -15,7 +22,7 @@ export class HmacService { * Use this when sending outbound callbacks so the receiver can verify. */ sign(payload: string): string { - return createHmac('sha256', this.secret).update(payload).digest('hex'); + return createHmac('sha256', this.getSecret()).update(payload).digest('hex'); } /** diff --git a/app/backend/src/main.ts b/app/backend/src/main.ts index b267a671..8aa0bfc1 100644 --- a/app/backend/src/main.ts +++ b/app/backend/src/main.ts @@ -1,8 +1,9 @@ import { NestFactory } from '@nestjs/core'; import { ValidationPipe, VersioningType } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; -import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; +import { SwaggerModule } from '@nestjs/swagger'; import { AppModule } from './app.module'; +import { buildSwaggerConfig } from './swagger.config'; import { LoggerService } from './logger/logger.service'; import { LoggingInterceptor } from './interceptors/logging.interceptor'; import { config as loadEnv } from 'dotenv'; @@ -78,62 +79,7 @@ async function bootstrap() { app.useGlobalInterceptors(new LoggingInterceptor(logger)); // Swagger/OpenAPI Documentation - const config = new DocumentBuilder() - .setTitle('ChainForge API') - .setDescription( - `API documentation for ChainForge platform - Humanitarian aid and verification system - -## API Versioning - -This API uses URI-based versioning. The current version is **v1**. - -### Version Format -All endpoints are prefixed with the version number: \`/api/v1/...\` - -### Supported Versions -| Version | Status | Description | -|---------|--------|-------------| -| v1 | Current | Active version with full support | - -### Deprecation Policy -- Deprecated endpoints will be marked with \`@Deprecated\` in the documentation -- Deprecated versions will be supported for at least 6 months after deprecation notice -- Clients will receive deprecation warnings via the \`Sunset\` HTTP header -- Migration guides will be provided for major version changes - -### Future Versions -When new versions are released: -- New endpoints will be available at \`/api/v2/...\`, etc. -- Previous versions remain accessible during the deprecation period -- Clients should monitor the API documentation for version updates`, - ) - .setVersion('1.0') - .addBearerAuth( - { - type: 'http', - scheme: 'bearer', - bearerFormat: 'JWT', - name: 'Authorization', - in: 'header', - description: 'Enter JWT token', - }, - 'JWT-auth', - ) - .addApiKey( - { - type: 'apiKey', - name: 'x-api-key', - in: 'header', - description: 'API key for external access', - }, - 'api-key', - ) - .addServer('http://localhost:3000/api/v1', 'Local Development (v1)') - .addServer('https://api.chainforge.app/api/v1', 'Staging (v1)') - .addServer('https://api.chainforge.app/api/v1', 'Production (v1)') - .build(); - - const document = SwaggerModule.createDocument(app, config); + const document = SwaggerModule.createDocument(app, buildSwaggerConfig()); SwaggerModule.setup('api/docs', app, document, { customSiteTitle: 'ChainForge API Docs', customfavIcon: 'https://chainforge.app/favicon.ico', diff --git a/app/backend/src/swagger.config.ts b/app/backend/src/swagger.config.ts new file mode 100644 index 00000000..ec34e31a --- /dev/null +++ b/app/backend/src/swagger.config.ts @@ -0,0 +1,58 @@ +import { DocumentBuilder } from '@nestjs/swagger'; + +export function buildSwaggerConfig() { + return new DocumentBuilder() + .setTitle('ChainForge API') + .setDescription( + `API documentation for ChainForge platform - Humanitarian aid and verification system + +## API Versioning + +This API uses URI-based versioning. The current version is **v1**. + +### Version Format +All endpoints are prefixed with the version number: \`/api/v1/...\` + +### Supported Versions +| Version | Status | Description | +|---------|--------|-------------| +| v1 | Current | Active version with full support | + +### Deprecation Policy +- Deprecated endpoints will be marked with \`@Deprecated\` in the documentation +- Deprecated versions will be supported for at least 6 months after deprecation notice +- Clients will receive deprecation warnings via the \`Sunset\` HTTP header +- Migration guides will be provided for major version changes + +### Future Versions +When new versions are released: +- New endpoints will be available at \`/api/v2/...\`, etc. +- Previous versions remain accessible during the deprecation period +- Clients should monitor the API documentation for version updates`, + ) + .setVersion('1.0') + .addBearerAuth( + { + type: 'http', + scheme: 'bearer', + bearerFormat: 'JWT', + name: 'Authorization', + in: 'header', + description: 'Enter JWT token', + }, + 'JWT-auth', + ) + .addApiKey( + { + type: 'apiKey', + name: 'x-api-key', + in: 'header', + description: 'API key for external access', + }, + 'api-key', + ) + .addServer('http://localhost:3000', 'Local Development') + .addServer('https://api.chainforge.app', 'Staging') + .addServer('https://api.chainforge.app', 'Production') + .build(); +} diff --git a/app/backend/src/verification/verification-inbox.controller.ts b/app/backend/src/verification/verification-inbox.controller.ts index e3391d9f..77fab360 100644 --- a/app/backend/src/verification/verification-inbox.controller.ts +++ b/app/backend/src/verification/verification-inbox.controller.ts @@ -17,6 +17,7 @@ import { ApiParam, ApiQuery, ApiBearerAuth, + ApiBody, ApiOkResponse, ApiBadRequestResponse, ApiUnauthorizedResponse, @@ -164,6 +165,15 @@ export class VerificationInboxController { @ApiBadRequestResponse({ description: 'Invalid request or verification already processed.', }) + @ApiBody({ + schema: { + type: 'object', + properties: { + nextStepMessage: { type: 'string' }, + internalNote: { type: 'string' }, + }, + }, + }) async approve( @Param('id') id: string, @Body() body: { nextStepMessage?: string; internalNote?: string }, @@ -212,6 +222,17 @@ export class VerificationInboxController { @ApiBadRequestResponse({ description: 'Invalid request or verification already processed.', }) + @ApiBody({ + schema: { + type: 'object', + required: ['rejectionReason'], + properties: { + rejectionReason: { type: 'string' }, + nextStepMessage: { type: 'string' }, + internalNote: { type: 'string' }, + }, + }, + }) async reject( @Param('id') id: string, @Body() @@ -265,6 +286,17 @@ export class VerificationInboxController { @ApiBadRequestResponse({ description: 'Invalid request or verification already processed.', }) + @ApiBody({ + schema: { + type: 'object', + required: ['rejectionReason', 'nextStepMessage'], + properties: { + rejectionReason: { type: 'string' }, + nextStepMessage: { type: 'string' }, + internalNote: { type: 'string' }, + }, + }, + }) async requestResubmission( @Param('id') id: string, @Body() @@ -353,6 +385,16 @@ export class VerificationInboxController { @ApiNotFoundResponse({ description: 'The specified verification request was not found.', }) + @ApiBody({ + schema: { + type: 'object', + required: ['content'], + properties: { + content: { type: 'string' }, + category: { type: 'string' }, + }, + }, + }) async addInternalNote( @Param('id') id: string, @Body() body: { content: string; category?: string }, diff --git a/app/frontend/openapi.json b/app/frontend/openapi.json new file mode 100644 index 00000000..c7f11262 --- /dev/null +++ b/app/frontend/openapi.json @@ -0,0 +1,6559 @@ +{ + "openapi": "3.0.0", + "paths": { + "/api/v1": { + "get": { + "description": "Returns a welcome message and API information. Part of v1 API.", + "operationId": "AppController_getHello_v1", + "parameters": [], + "responses": { + "200": { + "description": "Welcome message returned successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "message": "Welcome to ChainForge API", + "version": "v1", + "docs": "/api/docs" + } + } + } + } + } + }, + "summary": "Root endpoint (v1)", + "tags": [ + "App" + ] + } + }, + "/api/v1/health": { + "get": { + "description": "Returns process liveness details and service metadata. Part of v1 API.", + "operationId": "HealthController_check_v1", + "parameters": [], + "responses": { + "200": { + "description": "Service is alive and basic metadata retrieved.", + "content": { + "application/json": { + "schema": { + "example": { + "status": "ok", + "version": "1.0.0", + "timestamp": "2025-02-23T12:00:00.000Z" + } + } + } + } + } + }, + "summary": "Check system liveness and basic service metadata", + "tags": [ + "Health" + ] + } + }, + "/api/v1/deprecated-test": { + "get": { + "deprecated": true, + "description": "⚠️ **DEPRECATED**\n\n**Reason:** This endpoint is for testing deprecation headers.\n\n**Deprecated since:** 2025-01-01\n\n**Sunset date:** 2025-12-31\n\n**Alternative:** /api/v1/health\n\n**Migration guide:** https://docs.chainforge.app/migration", + "operationId": "AppController_deprecatedTest_v1", + "parameters": [], + "responses": { + "200": { + "description": "Success (Deprecated)", + "headers": { + "Deprecation": { + "description": "Deprecation date: 2025-01-01", + "schema": { + "type": "string" + } + }, + "Sunset": { + "description": "Sunset date: 2025-12-31", + "schema": { + "type": "string" + } + } + } + } + }, + "summary": "", + "tags": [ + "App" + ] + } + }, + "/api/v1/health/live": { + "get": { + "description": "Returns process-level liveness information. Intended for orchestration liveness checks.", + "operationId": "HealthController_liveness_v1", + "parameters": [], + "responses": { + "200": { + "description": "Process is alive.", + "content": { + "application/json": { + "schema": { + "example": { + "status": "ok", + "uptime": "2d 5h 12m 30s" + } + } + } + } + } + }, + "summary": "Liveness probe", + "tags": [ + "Health" + ] + } + }, + "/api/v1/health/ready": { + "get": { + "description": "Returns dependency readiness (database and optional Stellar RPC). Responds 503 when not ready.", + "operationId": "HealthController_readiness_v1", + "parameters": [], + "responses": { + "200": { + "description": "Service is ready to serve traffic.", + "content": { + "application/json": { + "schema": { + "example": { + "ready": true, + "dependencies": { + "database": "up", + "stellar": "up" + } + } + } + } + } + }, + "503": { + "description": "Service is not ready (one or more dependencies are down).", + "content": { + "application/json": { + "schema": { + "example": { + "ready": false, + "dependencies": { + "database": "down", + "stellar": "up" + } + } + } + } + } + } + }, + "summary": "Readiness probe", + "tags": [ + "Health" + ] + } + }, + "/api/v1/health/error": { + "get": { + "operationId": "HealthController_triggerError_v1", + "parameters": [], + "responses": { + "500": { + "description": "Test error triggered successfully." + } + }, + "summary": "Trigger an error for testing", + "tags": [ + "Health" + ] + } + }, + "/api/v1/health/onchain": { + "get": { + "description": "Performs a read-only contract call to verify connectivity to Soroban RPC and contract functionality. Requires authentication.", + "operationId": "HealthController_onchainHealth_v1", + "parameters": [], + "responses": { + "200": { + "description": "On-chain health check completed successfully" + }, + "503": { + "description": "On-chain health check failed" + } + }, + "summary": "On-chain contract health probe (internal use)", + "tags": [ + "Health" + ] + } + }, + "/api/v1/admin/ledger/backfill": { + "post": { + "description": "Start a backfill job to process a range of ledgers and populate missing ledger entries. Idempotent - can be run repeatedly without duplicating data.", + "operationId": "LedgerAdminController_triggerBackfill_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "startLedger": { + "type": "number", + "description": "Starting ledger sequence number" + }, + "endLedger": { + "type": "number", + "description": "Ending ledger sequence number" + }, + "campaignId": { + "type": "string", + "description": "Optional campaign ID to filter" + }, + "batchSize": { + "type": "number", + "description": "Number of ledgers to process per batch (default: 100)" + } + }, + "required": [ + "startLedger", + "endLedger" + ] + } + } + } + }, + "responses": { + "200": { + "description": "Backfill job queued successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "jobId": "job_123", + "startLedger": 1000, + "endLedger": 2000, + "status": "queued", + "processedCount": 0, + "totalCount": 1001 + } + } + } + } + }, + "400": { + "description": "Invalid request parameters." + }, + "401": { + "description": "Unauthorized - valid JWT token required." + }, + "403": { + "description": "Access denied - admin role required." + } + }, + "summary": "Trigger ledger backfill job", + "tags": [ + "Ledger Admin" + ] + } + }, + "/api/v1/admin/ledger/backfill/{jobId}": { + "get": { + "description": "Retrieve the current status of a backfill job.", + "operationId": "LedgerAdminController_getBackfillStatus_v1", + "parameters": [ + { + "name": "jobId", + "required": true, + "in": "path", + "description": "Job ID returned from triggerBackfill", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Backfill status retrieved successfully." + }, + "401": { + "description": "Unauthorized - valid JWT token required." + }, + "403": { + "description": "Access denied - admin role required." + } + }, + "summary": "Get backfill job status", + "tags": [ + "Ledger Admin" + ] + } + }, + "/api/v1/admin/ledger/reconcile": { + "post": { + "description": "Start a reconciliation job to compare on-chain data against stored records and detect discrepancies.", + "operationId": "LedgerAdminController_triggerReconciliation_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "startLedger": { + "type": "number", + "description": "Starting ledger sequence number" + }, + "endLedger": { + "type": "number", + "description": "Ending ledger sequence number" + }, + "campaignId": { + "type": "string", + "description": "Optional campaign ID to filter" + }, + "thresholdPercent": { + "type": "number", + "description": "Threshold percentage for amount mismatch (default: 5)" + } + }, + "required": [ + "startLedger", + "endLedger" + ] + } + } + } + }, + "responses": { + "200": { + "description": "Reconciliation job queued successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "jobId": "job_456", + "startLedger": 1000, + "endLedger": 2000, + "status": "queued", + "totalLedgers": 1001, + "checkedLedgers": 0, + "discrepancies": [], + "summary": { + "totalDiscrepancies": 0, + "bySeverity": { + "low": 0, + "medium": 0, + "high": 0 + }, + "byType": { + "missing": 0, + "amount_mismatch": 0, + "count_mismatch": 0 + } + }, + "actionable": false + } + } + } + } + }, + "400": { + "description": "Invalid request parameters." + }, + "401": { + "description": "Unauthorized - valid JWT token required." + }, + "403": { + "description": "Access denied - admin role required." + } + }, + "summary": "Trigger ledger reconciliation job", + "tags": [ + "Ledger Admin" + ] + } + }, + "/api/v1/admin/ledger/reconcile/{jobId}": { + "get": { + "description": "Retrieve the current status and report of a reconciliation job.", + "operationId": "LedgerAdminController_getReconciliationStatus_v1", + "parameters": [ + { + "name": "jobId", + "required": true, + "in": "path", + "description": "Job ID returned from triggerReconciliation", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Reconciliation status retrieved successfully." + }, + "401": { + "description": "Unauthorized - valid JWT token required." + }, + "403": { + "description": "Access denied - admin role required." + } + }, + "summary": "Get reconciliation job status", + "tags": [ + "Ledger Admin" + ] + } + }, + "/api/v1/jobs/status": { + "get": { + "description": "Retrieves the count of waiting, active, completed, failed, and delayed jobs for all system queues.", + "operationId": "JobsController_getStatus_v1", + "parameters": [], + "responses": { + "200": { + "description": "Queue statuses retrieved successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "verification": { + "name": "verification", + "waiting": 0, + "active": 0, + "completed": 10, + "failed": 0, + "delayed": 0 + }, + "notifications": { + "name": "notifications", + "waiting": 0, + "active": 0, + "completed": 5, + "failed": 0, + "delayed": 0 + }, + "onchain": { + "name": "onchain", + "waiting": 0, + "active": 0, + "completed": 2, + "failed": 0, + "delayed": 0 + } + } + } + } + } + } + }, + "summary": "Get status of all background job queues", + "tags": [ + "Jobs" + ] + } + }, + "/api/v1/jobs/health": { + "get": { + "description": "Checks if any core queues are degraded (too many waiting or failed jobs).", + "operationId": "JobsController_getHealth_v1", + "parameters": [], + "responses": { + "200": { + "description": "" + } + }, + "summary": "Get overall health of background job queues", + "tags": [ + "Jobs" + ] + } + }, + "/api/v1/metrics": { + "get": { + "operationId": "PrometheusController_index_v1", + "parameters": [], + "responses": { + "200": { + "description": "" + } + }, + "tags": [ + "Prometheus" + ] + } + }, + "/api/v1/aid/campaigns": { + "post": { + "description": "Initializes a new aid campaign with provided metadata. Requires appropriate permissions.", + "operationId": "AidController_createCampaign_v1", + "parameters": [], + "responses": { + "201": { + "description": "Campaign created successfully." + }, + "400": { + "description": "Invalid input parameters." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Create a new campaign", + "tags": [ + "Aid" + ] + } + }, + "/api/v1/aid/campaigns/{id}": { + "patch": { + "description": "Modifies an existing campaign. Only provided fields will be updated.", + "operationId": "AidController_updateCampaign_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Campaign updated successfully." + }, + "400": { + "description": "Invalid update data." + }, + "404": { + "description": "The specified campaign was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Update a campaign", + "tags": [ + "Aid" + ] + }, + "delete": { + "description": "Soft-archives a campaign, making it invisible to standard listings.", + "operationId": "AidController_archiveCampaign_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Campaign archived successfully." + }, + "404": { + "description": "The specified campaign was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Archive a campaign", + "tags": [ + "Aid" + ] + } + }, + "/api/v1/aid/claims/{id}/status": { + "put": { + "description": "Moves a claim from one status to another (e.g., pending -> approved).", + "operationId": "AidController_transitionClaim_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Claim status transitioned successfully." + }, + "400": { + "description": "Invalid status transition requested." + }, + "404": { + "description": "The specified claim was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Transition a claim status", + "tags": [ + "Aid" + ] + } + }, + "/api/v1/aid/webhook": { + "post": { + "description": "Receives notifications from the AI service when background tasks complete.", + "operationId": "AidController_handleTaskWebhook_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiTaskWebhookDto" + } + } + } + }, + "responses": { + "200": { + "description": "Webhook received successfully." + }, + "400": { + "description": "Invalid webhook payload." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Webhook for AI task notifications", + "tags": [ + "Aid" + ] + } + }, + "/api/v1/verification/claims/{id}/enqueue": { + "post": { + "description": "Add a claim to the verification queue for async processing. Returns immediately with job ID.", + "operationId": "VerificationController_enqueueVerification_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Unique identifier of the claim to verify", + "schema": { + "example": "clv789xyz123", + "type": "string" + } + } + ], + "responses": { + "202": { + "description": "Verification job enqueued successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "jobId": "12345", + "claimId": "clv789xyz123", + "status": "queued", + "message": "Verification job enqueued successfully" + } + } + } + } + }, + "400": { + "description": "Invalid claim ID or malformed request." + }, + "401": { + "description": "Invalid or missing API key." + }, + "404": { + "description": "The requested claim could not be found." + } + }, + "security": [ + { + "x-api-key": [] + } + ], + "summary": "Enqueue claim verification job", + "tags": [ + "Verification" + ] + } + }, + "/api/v1/verification/metrics": { + "get": { + "description": "Retrieve current queue statistics including waiting, active, completed, and failed job counts", + "operationId": "VerificationController_getMetrics_v1", + "parameters": [], + "responses": { + "200": { + "description": "Queue metrics retrieved successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "waiting": 5, + "active": 2, + "completed": 150, + "failed": 3, + "total": 160 + } + } + } + } + }, + "401": { + "description": "Invalid or missing API key." + } + }, + "security": [ + { + "x-api-key": [] + } + ], + "summary": "Get verification queue metrics", + "tags": [ + "Verification" + ] + } + }, + "/api/v1/verification/start": { + "post": { + "description": "Start a verification session. Sends an OTP to the given email or phone. Rate-limited per identifier.", + "operationId": "VerificationController_startVerification_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StartVerificationDto" + } + } + } + }, + "responses": { + "200": { + "description": "Verification started; code sent to channel.", + "content": { + "application/json": { + "examples": { + "email": { + "summary": "Email verification started", + "value": { + "sessionId": "ses_email_123", + "channel": "email", + "expiresAt": "2025-02-19T12:10:00.000Z", + "message": "Verification code sent to email. Code expires in 10 minutes." + } + }, + "phone": { + "summary": "Phone verification started", + "value": { + "sessionId": "ses_phone_456", + "channel": "phone", + "expiresAt": "2025-02-19T12:10:00.000Z", + "message": "Verification code sent to phone. Code expires in 10 minutes." + } + } + } + } + } + }, + "400": { + "description": "Invalid input parameters or rate limit exceeded for this identifier." + } + }, + "security": [ + { + "x-api-key": [] + } + ], + "summary": "Start verification flow (OTP/email/phone)", + "tags": [ + "Verification" + ] + } + }, + "/api/v1/verification/resend": { + "post": { + "description": "Resend OTP for an existing pending session. Limited resends per session.", + "operationId": "VerificationController_resendVerification_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResendVerificationDto" + } + } + } + }, + "responses": { + "200": { + "description": "New verification code sent successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "sessionId": "clv789xyz123", + "expiresAt": "2025-02-19T12:10:00.000Z", + "message": "New verification code sent." + } + } + } + } + }, + "400": { + "description": "Session is inactive, expired, or resend limit has been reached." + }, + "404": { + "description": "The specified verification session was not found." + } + }, + "security": [ + { + "x-api-key": [] + } + ], + "summary": "Resend verification code", + "tags": [ + "Verification" + ] + } + }, + "/api/v1/verification/complete": { + "post": { + "description": "Submit the OTP code to complete the verification. Attempts are rate-limited per session.", + "operationId": "VerificationController_completeVerification_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CompleteVerificationDto" + } + } + } + }, + "responses": { + "200": { + "description": "Verification completed successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "sessionId": "clv789xyz123", + "verified": true, + "message": "Verification completed successfully." + } + } + } + } + }, + "400": { + "description": "Invalid code, session expired, or too many failed attempts." + }, + "404": { + "description": "The specified verification session was not found." + } + }, + "security": [ + { + "x-api-key": [] + } + ], + "summary": "Complete verification with OTP", + "tags": [ + "Verification" + ] + } + }, + "/api/v1/verification": { + "post": { + "description": "Submit identity documents and information for verification. Supports document uploads and biometric data. Part of v1 API.", + "operationId": "VerificationController_create_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateVerificationDto" + } + }, + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/CreateVerificationDto" + } + } + } + }, + "responses": { + "201": { + "description": "Verification request submitted successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "id": "clv789xyz123", + "userId": "clu456def789", + "documentType": "NATIONAL_ID", + "status": "PENDING", + "submittedAt": "2025-01-23T11:00:00.000Z", + "verificationCode": "VER-2025-0123" + } + } + } + } + }, + "400": { + "description": "Invalid verification data or unsupported document format." + }, + "401": { + "description": "Missing or invalid authentication credentials." + } + }, + "security": [ + { + "x-api-key": [] + } + ], + "summary": "Submit identity verification request (v1)", + "tags": [ + "Verification" + ] + } + }, + "/api/v1/verification/claims/{id}": { + "get": { + "description": "Retrieve the current verification status and details of a claim", + "operationId": "VerificationController_findClaim_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Unique identifier of the claim", + "schema": { + "example": "clv789xyz123", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Claim verification status retrieved successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "id": "clv789xyz123", + "status": "verified", + "verificationScore": 0.85, + "verificationResult": { + "score": 0.85, + "confidence": 0.92, + "details": { + "factors": [ + "Document authenticity verified", + "Identity cross-reference passed" + ], + "riskLevel": "low" + }, + "processedAt": "2025-01-23T14:30:00.000Z" + }, + "verifiedAt": "2025-01-23T14:30:00.000Z" + } + } + } + } + }, + "401": { + "description": "Unauthorized - valid JWT token required." + }, + "404": { + "description": "The specified claim could not be found." + } + }, + "security": [ + { + "x-api-key": [] + }, + { + "JWT-auth": [] + } + ], + "summary": "Get claim verification status", + "tags": [ + "Verification" + ] + } + }, + "/api/v1/verification/{id}": { + "get": { + "description": "Retrieve the current status and details of a verification request. Part of v1 API.", + "operationId": "VerificationController_findOne_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Unique identifier of the verification request", + "schema": { + "example": "clv789xyz123", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Verification status retrieved successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "id": "clv789xyz123", + "userId": "clu456def789", + "documentType": "NATIONAL_ID", + "status": "APPROVED", + "submittedAt": "2025-01-23T11:00:00.000Z", + "reviewedAt": "2025-01-23T14:30:00.000Z", + "verificationCode": "VER-2025-0123", + "notes": "All documents verified successfully" + } + } + } + } + }, + "401": { + "description": "Unauthorized - valid JWT token required." + }, + "404": { + "description": "The specified verification request was not found." + } + }, + "security": [ + { + "x-api-key": [] + }, + { + "JWT-auth": [] + } + ], + "summary": "Get verification status (v1)", + "tags": [ + "Verification" + ] + } + }, + "/api/v1/verification/user/{userId}": { + "get": { + "description": "Retrieve all verification requests for a specific user. Part of v1 API.", + "operationId": "VerificationController_findByUser_v1", + "parameters": [ + { + "name": "userId", + "required": true, + "in": "path", + "description": "Unique identifier of the user", + "schema": { + "example": "clu456def789", + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "User verification history retrieved successfully.", + "content": { + "application/json": { + "schema": { + "example": [ + { + "id": "clv789xyz123", + "documentType": "NATIONAL_ID", + "status": "APPROVED", + "submittedAt": "2025-01-23T11:00:00.000Z", + "reviewedAt": "2025-01-23T14:30:00.000Z" + } + ] + } + } + } + }, + "401": { + "description": "Unauthorized - valid JWT token required." + } + }, + "security": [ + { + "x-api-key": [] + }, + { + "JWT-auth": [] + } + ], + "summary": "Get user verification history (v1)", + "tags": [ + "Verification" + ] + } + }, + "/api/v1/verification/{id}/complete": { + "post": { + "description": "Updates the status of a verification request to complete and logs the action.", + "operationId": "VerificationController_update_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Unique identifier of the verification request", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Verification status updated successfully." + }, + "404": { + "description": "The specified verification request was not found." + } + }, + "security": [ + { + "x-api-key": [] + } + ], + "summary": "Mark verification as complete", + "tags": [ + "Verification" + ] + } + }, + "/api/v1/verification/{id}/notes": { + "post": { + "description": "Adds a secure internal note for staff review only.", + "operationId": "VerificationController_addNote_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateInternalNoteDto" + } + } + } + }, + "responses": { + "201": { + "description": "Internal note added successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InternalNoteResponseDto" + } + } + } + }, + "403": { + "description": "Access denied - staff role required." + } + }, + "security": [ + { + "x-api-key": [] + } + ], + "summary": "Add an internal note to a verification record", + "tags": [ + "Verification" + ] + }, + "get": { + "description": "Retrieves all internal notes for a specific verification.", + "operationId": "VerificationController_getNotes_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Internal notes retrieved successfully.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InternalNoteResponseDto" + } + } + } + } + }, + "403": { + "description": "Access denied - staff role required." + } + }, + "security": [ + { + "x-api-key": [] + } + ], + "summary": "List internal notes for a verification record", + "tags": [ + "Verification" + ] + } + }, + "/api/v1/verification-inbox": { + "get": { + "description": "Retrieve verification requests with filtering and pagination. Shows pending_review, approved, rejected, and needs_resubmission states.", + "operationId": "VerificationInboxController_getInbox_v1", + "parameters": [ + { + "name": "status", + "required": false, + "in": "query", + "description": "Filter by verification status", + "schema": { + "enum": [ + "pending_review", + "approved", + "rejected", + "needs_resubmission" + ], + "type": "string" + } + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (default: 1)", + "schema": { + "type": "number" + } + }, + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page (default: 20)", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "Verification inbox retrieved successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "items": [ + { + "id": "clv789xyz123", + "status": "pending_review", + "createdAt": "2025-01-23T11:00:00.000Z", + "reviewedAt": null, + "nextStepMessage": "Review identity documents for authenticity", + "deepLink": "/verification/clv789xyz123" + } + ], + "total": 45, + "page": 1, + "limit": 20, + "totalPages": 3 + } + } + } + } + }, + "401": { + "description": "Unauthorized - valid JWT token required." + }, + "403": { + "description": "Access denied - operator or admin role required." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get verification inbox", + "tags": [ + "Verification Inbox" + ] + } + }, + "/api/v1/verification-inbox/stats": { + "get": { + "description": "Retrieve counts of verification requests by status for dashboard display.", + "operationId": "VerificationInboxController_getStats_v1", + "parameters": [], + "responses": { + "200": { + "description": "Statistics retrieved successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "pending_review": 15, + "approved": 120, + "rejected": 8, + "needs_resubmission": 5, + "total": 148 + } + } + } + } + }, + "401": { + "description": "Unauthorized - valid JWT token required." + }, + "403": { + "description": "Access denied - operator or admin role required." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get verification inbox statistics", + "tags": [ + "Verification Inbox" + ] + } + }, + "/api/v1/verification-inbox/{id}/approve": { + "post": { + "description": "Mark a verification request as approved and set next step messaging.", + "operationId": "VerificationInboxController_approve_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Unique identifier of the verification request", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "nextStepMessage": { + "type": "string" + }, + "internalNote": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Verification approved successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "id": "clv789xyz123", + "status": "approved", + "reviewedAt": "2025-01-23T14:30:00.000Z", + "nextStepMessage": "Verification approved. Proceed to disbursement." + } + } + } + } + }, + "400": { + "description": "Invalid request or verification already processed." + }, + "404": { + "description": "The specified verification request was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Approve verification request", + "tags": [ + "Verification Inbox" + ] + } + }, + "/api/v1/verification-inbox/{id}/reject": { + "post": { + "description": "Mark a verification request as rejected with reason and next step messaging.", + "operationId": "VerificationInboxController_reject_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Unique identifier of the verification request", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "rejectionReason" + ], + "properties": { + "rejectionReason": { + "type": "string" + }, + "nextStepMessage": { + "type": "string" + }, + "internalNote": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Verification rejected successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "id": "clv789xyz123", + "status": "rejected", + "reviewedAt": "2025-01-23T14:30:00.000Z", + "rejectionReason": "Document appears fraudulent", + "nextStepMessage": "Please resubmit with valid documentation" + } + } + } + } + }, + "400": { + "description": "Invalid request or verification already processed." + }, + "404": { + "description": "The specified verification request was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Reject verification request", + "tags": [ + "Verification Inbox" + ] + } + }, + "/api/v1/verification-inbox/{id}/request-resubmission": { + "post": { + "description": "Mark a verification request as needing resubmission with specific requirements.", + "operationId": "VerificationInboxController_requestResubmission_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Unique identifier of the verification request", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "rejectionReason", + "nextStepMessage" + ], + "properties": { + "rejectionReason": { + "type": "string" + }, + "nextStepMessage": { + "type": "string" + }, + "internalNote": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Resubmission requested successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "id": "clv789xyz123", + "status": "needs_resubmission", + "reviewedAt": "2025-01-23T14:30:00.000Z", + "rejectionReason": "Document expired", + "nextStepMessage": "Please submit a current government-issued ID" + } + } + } + } + }, + "400": { + "description": "Invalid request or verification already processed." + }, + "404": { + "description": "The specified verification request was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Request resubmission for verification", + "tags": [ + "Verification Inbox" + ] + } + }, + "/api/v1/verification-inbox/{id}": { + "get": { + "description": "Retrieve detailed information about a specific verification request including review history.", + "operationId": "VerificationInboxController_getDetails_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Unique identifier of the verification request", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Verification details retrieved successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "id": "clv789xyz123", + "status": "pending_review", + "createdAt": "2025-01-23T11:00:00.000Z", + "reviewedAt": null, + "reviewedBy": null, + "rejectionReason": null, + "nextStepMessage": "Review identity documents for authenticity", + "deepLink": "/verification/clv789xyz123" + } + } + } + } + }, + "401": { + "description": "Unauthorized - valid JWT token required." + }, + "404": { + "description": "The specified verification request was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get verification request details", + "tags": [ + "Verification Inbox" + ] + } + }, + "/api/v1/verification-inbox/{id}/notes": { + "post": { + "description": "Add an internal note visible only to reviewers. The action is recorded in the audit trail.", + "operationId": "VerificationInboxController_addInternalNote_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Unique identifier of the verification request", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "content" + ], + "properties": { + "content": { + "type": "string" + }, + "category": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Internal note added successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "id": "note-abc123", + "entityType": "verification", + "entityId": "clv789xyz123", + "content": "Contacted applicant for additional documents.", + "authorId": "reviewer-001", + "category": "follow_up", + "createdAt": "2025-01-23T15:00:00.000Z" + } + } + } + } + }, + "404": { + "description": "The specified verification request was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Add internal note to verification request", + "tags": [ + "Verification Inbox" + ] + }, + "get": { + "description": "Retrieve all internal notes attached to a verification request.", + "operationId": "VerificationInboxController_getInternalNotes_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Unique identifier of the verification request", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Internal notes retrieved successfully." + }, + "404": { + "description": "The specified verification request was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "List internal notes for a verification request", + "tags": [ + "Verification Inbox" + ] + } + }, + "/api/v1/audit": { + "get": { + "description": "Retrieves a filtered list of audit logs based on entity, actor, or time range.", + "operationId": "AuditController_getLogs_v1", + "parameters": [ + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page (default: 50, max: 200)", + "schema": {} + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (default: 1)", + "schema": {} + }, + { + "name": "endTime", + "required": false, + "in": "query", + "description": "ISO string", + "schema": {} + }, + { + "name": "startTime", + "required": false, + "in": "query", + "description": "ISO string", + "schema": {} + }, + { + "name": "action", + "required": false, + "in": "query", + "schema": {} + }, + { + "name": "actorId", + "required": false, + "in": "query", + "schema": {} + }, + { + "name": "entityId", + "required": false, + "in": "query", + "schema": {} + }, + { + "name": "entity", + "required": false, + "in": "query", + "schema": {} + } + ], + "responses": { + "200": { + "description": "Audit logs retrieved successfully." + }, + "401": { + "description": "Missing or invalid authentication credentials." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Query audit logs", + "tags": [ + "Audit" + ] + } + }, + "/api/v1/audit/export": { + "get": { + "description": "Exports anonymized audit logs as JSON or CSV with pagination and date-range filtering. Sensitive actor and entity IDs are replaced with deterministic SHA-256 hashes.", + "operationId": "AuditController_exportLogs_v1", + "parameters": [ + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page (default: 50, max: 200)", + "schema": {} + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (default: 1)", + "schema": {} + }, + { + "name": "actorId", + "required": false, + "in": "query", + "description": "Filter by actor ID", + "schema": {} + }, + { + "name": "action", + "required": false, + "in": "query", + "description": "Filter by action type", + "schema": {} + }, + { + "name": "entity", + "required": false, + "in": "query", + "description": "Filter by entity type", + "schema": {} + }, + { + "name": "to", + "required": false, + "in": "query", + "description": "End date (ISO string)", + "schema": {} + }, + { + "name": "from", + "required": false, + "in": "query", + "description": "Start date (ISO string)", + "schema": {} + }, + { + "name": "format", + "required": false, + "in": "query", + "description": "Export format (default: json)", + "schema": { + "enum": [ + "json", + "csv" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Audit logs exported successfully." + }, + "401": { + "description": "Missing or invalid authentication credentials." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Export anonymized audit logs", + "tags": [ + "Audit" + ] + } + }, + "/api/v1/notifications/outbox": { + "get": { + "description": "Returns all NotificationOutbox records in pending or enqueued status whose scheduledFor is more than 10 minutes in the past.", + "operationId": "OutboxController_listStuck_v1", + "parameters": [], + "responses": { + "200": { + "description": "Stuck outbox records returned." + }, + "401": { + "description": "Missing or invalid API key." + }, + "403": { + "description": "Insufficient role (requires admin or operator)." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "List stuck notification outbox records", + "tags": [ + "Notifications Outbox" + ] + } + }, + "/api/v1/notifications/outbox/{id}": { + "get": { + "description": "Returns the NotificationOutbox record for the given id.", + "operationId": "OutboxController_getOne_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Outbox record returned." + }, + "401": { + "description": "Missing or invalid API key." + }, + "403": { + "description": "Insufficient role (requires admin or operator)." + }, + "404": { + "description": "Outbox record not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get a single notification outbox record", + "tags": [ + "Notifications Outbox" + ] + } + }, + "/api/v1/test-error/generic": { + "get": { + "operationId": "TestErrorController_getGenericError_v1", + "parameters": [], + "responses": { + "500": { + "description": "Generic error triggered." + } + }, + "summary": "Trigger a generic Error", + "tags": [ + "Test Error" + ] + } + }, + "/api/v1/test-error/bad-request": { + "get": { + "operationId": "TestErrorController_getBadRequest_v1", + "parameters": [], + "responses": { + "400": { + "description": "Bad request triggered." + } + }, + "summary": "Trigger a BadRequestException", + "tags": [ + "Test Error" + ] + } + }, + "/api/v1/test-error/internal-server-error": { + "get": { + "operationId": "TestErrorController_getInternalServerError_v1", + "parameters": [], + "responses": { + "500": { + "description": "Internal server error triggered." + } + }, + "summary": "Trigger an InternalServerErrorException", + "tags": [ + "Test Error" + ] + } + }, + "/api/v1/test-error/unauthorized": { + "get": { + "operationId": "TestErrorController_getUnauthorized_v1", + "parameters": [], + "responses": { + "401": { + "description": "Unauthorized error triggered." + } + }, + "summary": "Trigger an UnauthorizedException", + "tags": [ + "Test Error" + ] + } + }, + "/api/v1/test-error/forbidden": { + "get": { + "operationId": "TestErrorController_getForbidden_v1", + "parameters": [], + "responses": { + "403": { + "description": "Forbidden error triggered." + } + }, + "summary": "Trigger a ForbiddenException", + "tags": [ + "Test Error" + ] + } + }, + "/api/v1/test-error/not-found": { + "get": { + "operationId": "TestErrorController_getNotFound_v1", + "parameters": [], + "responses": { + "404": { + "description": "Not found error triggered." + } + }, + "summary": "Trigger a NotFoundException", + "tags": [ + "Test Error" + ] + } + }, + "/api/v1/test-error/validation-error": { + "post": { + "operationId": "TestErrorController_postValidationError_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateVerificationDto" + } + } + } + }, + "responses": { + "200": { + "description": "Validation passed." + }, + "400": { + "description": "Validation failed." + } + }, + "summary": "Trigger a validation error via Post body", + "tags": [ + "Test Error" + ] + } + }, + "/api/v1/test-error/prisma-error-simulation": { + "get": { + "operationId": "TestErrorController_getPrismaErrorSimulation_v1", + "parameters": [], + "responses": { + "500": { + "description": "Database error simulated." + } + }, + "summary": "Simulate a Prisma database error", + "tags": [ + "Test Error" + ] + } + }, + "/api/v1/campaigns": { + "post": { + "operationId": "CampaignsController_create_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateCampaignDto" + } + } + } + }, + "responses": { + "201": { + "description": "Campaign created successfully." + }, + "400": { + "description": "Invalid input parameters or malformed request body." + }, + "401": { + "description": "Missing or invalid authentication credentials." + }, + "403": { + "description": "Access denied - insufficient permissions for this operation." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Create a campaign", + "tags": [ + "Campaigns" + ] + }, + "get": { + "description": "Retrieves campaigns. NGO operators only see their own organization's campaigns.", + "operationId": "CampaignsController_list_v1", + "parameters": [ + { + "name": "includeArchived", + "required": true, + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "List of campaigns retrieved successfully." + }, + "401": { + "description": "Missing or invalid authentication credentials." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "List all campaigns", + "tags": [ + "Campaigns" + ] + } + }, + "/api/v1/campaigns/{id}": { + "get": { + "description": "Retrieves metadata and status for a specific campaign.", + "operationId": "CampaignsController_get_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Campaign details retrieved successfully." + }, + "401": { + "description": "Missing or invalid authentication credentials." + }, + "404": { + "description": "The specified campaign was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get campaign details", + "tags": [ + "Campaigns" + ] + }, + "patch": { + "description": "Modifies existing campaign properties. Only provided fields are updated.", + "operationId": "CampaignsController_update_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateCampaignDto" + } + } + } + }, + "responses": { + "200": { + "description": "Campaign updated successfully." + }, + "400": { + "description": "Invalid update data or malformed request body." + }, + "401": { + "description": "Missing or invalid authentication credentials." + }, + "403": { + "description": "Access denied - insufficient permissions." + }, + "404": { + "description": "The specified campaign was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Update a campaign", + "tags": [ + "Campaigns" + ] + } + }, + "/api/v1/campaigns/{id}/archive": { + "patch": { + "description": "Marks a campaign as archived. Archived campaigns are hidden from general listings.", + "operationId": "CampaignsController_archive_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Campaign archived successfully." + }, + "401": { + "description": "Missing or invalid authentication credentials." + }, + "403": { + "description": "Access denied - insufficient permissions." + }, + "404": { + "description": "The specified campaign was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Archive campaign (soft archive)", + "tags": [ + "Campaigns" + ] + } + }, + "/api/v1/campaigns/{id}/balance": { + "get": { + "description": "Returns the current locked, disbursed, and available budget for a campaign. Locked balance accounts for all active (non-cancelled, non-disbursed) claims. Cancelled claims release their locked amount back to available.", + "operationId": "CampaignsController_getBalance_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Campaign balance retrieved successfully.", + "content": { + "application/json": { + "schema": { + "properties": { + "campaignId": { + "type": "string" + }, + "budget": { + "type": "number", + "description": "Total campaign budget." + }, + "lockedAmount": { + "type": "number", + "description": "Amount locked by active claims." + }, + "disbursedAmount": { + "type": "number", + "description": "Amount already disbursed." + }, + "availableBudget": { + "type": "number", + "description": "Remaining available budget." + } + } + } + } + } + }, + "403": { + "description": "Access denied - operator role required." + }, + "404": { + "description": "Campaign not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get campaign balance summary", + "tags": [ + "Campaigns" + ] + } + }, + "/api/v1/campaigns/{id}/budget-summary": { + "get": { + "description": "Returns the total, locked, disbursed, and available budget for a campaign.", + "operationId": "CampaignsController_getBudgetSummary_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Campaign budget summary retrieved successfully.", + "content": { + "application/json": { + "schema": { + "properties": { + "campaignId": { + "type": "string" + }, + "budget": { + "type": "number" + }, + "locked": { + "type": "number" + }, + "disbursed": { + "type": "number" + }, + "available": { + "type": "number" + } + } + } + } + } + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get campaign budget summary", + "tags": [ + "Campaigns" + ] + } + }, + "/api/v1/campaigns/export": { + "get": { + "description": "Exports campaign summaries as CSV with support for date range, status, organization, and pagination filters. Excludes sensitive internal metadata and deleted records.", + "operationId": "CampaignsController_exportCampaigns_v1", + "parameters": [ + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page (default: 50, max: 200)", + "schema": {} + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (default: 1)", + "schema": {} + }, + { + "name": "ngoId", + "required": false, + "in": "query", + "description": "NGO ID filter", + "schema": {} + }, + { + "name": "orgId", + "required": false, + "in": "query", + "description": "Organization ID filter", + "schema": {} + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Campaign status filter", + "schema": {} + }, + { + "name": "to", + "required": false, + "in": "query", + "description": "End date (ISO string)", + "schema": {} + }, + { + "name": "from", + "required": false, + "in": "query", + "description": "Start date (ISO string)", + "schema": {} + } + ], + "responses": { + "200": { + "description": "Campaigns exported successfully.", + "content": { + "text/csv": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication credentials." + }, + "403": { + "description": "Access denied - operator or admin role required." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Export campaigns as CSV", + "tags": [ + "Campaigns" + ] + } + }, + "/api/v1/claims": { + "post": { + "description": "Initializes a new claim for a specific campaign.", + "operationId": "ClaimsController_create_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateClaimDto" + } + } + } + }, + "responses": { + "201": { + "description": "Claim created successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateClaimDto" + } + } + } + }, + "400": { + "description": "Invalid input parameters." + }, + "404": { + "description": "The specified campaign was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Create a claim", + "tags": [ + "Onchain Proxy" + ] + }, + "get": { + "description": "Retrieves a list of all claims across all campaigns.", + "operationId": "ClaimsController_findAll_v1", + "parameters": [], + "responses": { + "200": { + "description": "List of all claims retrieved successfully." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "List all claims", + "tags": [ + "Onchain Proxy" + ] + } + }, + "/api/v1/claims/{id}": { + "get": { + "description": "Retrieves the current details and status of a specific claim.", + "operationId": "ClaimsController_findOne_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Claim details retrieved successfully." + }, + "404": { + "description": "The specified claim was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get claim details", + "tags": [ + "Onchain Proxy" + ] + } + }, + "/api/v1/claims/{id}/verify": { + "post": { + "description": "Marks a claim as verified. Requires operator or admin role.", + "operationId": "ClaimsController_verify_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Claim status transitioned to verified successfully." + }, + "400": { + "description": "Invalid status transition." + }, + "403": { + "description": "Access denied - insufficient permissions." + }, + "404": { + "description": "The specified claim was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Verify a claim", + "tags": [ + "Onchain Proxy" + ] + } + }, + "/api/v1/claims/{id}/approve": { + "post": { + "description": "Approves a verified claim. Requires admin role.", + "operationId": "ClaimsController_approve_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Claim approved successfully (verified → approved)." + }, + "400": { + "description": "Invalid status transition." + }, + "403": { + "description": "Access denied - admin role required." + }, + "404": { + "description": "The specified claim was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Approve a claim", + "tags": [ + "Onchain Proxy" + ] + } + }, + "/api/v1/claims/{id}/disburse": { + "post": { + "description": "Initiates on-chain disbursement for an approved claim. Requires admin role.", + "operationId": "ClaimsController_disburse_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "On-chain disbursement initiated or completed successfully.", + "content": { + "application/json": { + "examples": { + "success": { + "summary": "Successful on-chain disbursement", + "value": { + "id": "claim_123", + "status": "disbursed", + "transactionHash": "0x123...abc", + "amount": "100.50" + } + }, + "pending": { + "summary": "Disbursement pending on-chain", + "value": { + "id": "claim_123", + "status": "disbursing", + "message": "Check back for final transaction hash." + } + } + } + } + } + }, + "400": { + "description": "Invalid status transition or account state." + }, + "403": { + "description": "Access denied - admin role required." + }, + "404": { + "description": "The specified claim was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Disburse funds for a claim", + "tags": [ + "Onchain Proxy" + ] + } + }, + "/api/v1/claims/{id}/archive": { + "patch": { + "description": "Soft-archives a claim, hiding it from general listings.", + "operationId": "ClaimsController_archive_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Claim archived successfully." + }, + "400": { + "description": "Invalid status transition." + }, + "404": { + "description": "The specified claim was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Archive a claim", + "tags": [ + "Onchain Proxy" + ] + } + }, + "/api/v1/claims/{id}/receipt": { + "get": { + "description": "Generates a shareable receipt for the specified claim.", + "operationId": "ClaimsController_getReceipt_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Claim receipt generated successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClaimReceiptDto" + } + } + } + }, + "404": { + "description": "The specified claim was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get claim receipt", + "tags": [ + "Onchain Proxy" + ] + } + }, + "/api/v1/claims/{id}/receipt/share": { + "post": { + "description": "Generates and optionally sends the claim receipt via email or SMS.", + "operationId": "ClaimsController_shareReceipt_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SendReceiptShareDto" + } + } + } + }, + "responses": { + "200": { + "description": "Receipt generated and sharing initiated successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClaimShareResponseDto" + } + } + } + }, + "400": { + "description": "Invalid share parameters." + }, + "404": { + "description": "The specified claim was not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Share claim receipt", + "tags": [ + "Onchain Proxy" + ] + } + }, + "/api/v1/claims/{id}/notes": { + "post": { + "description": "Adds a secure internal note for staff review only.", + "operationId": "ClaimsController_addNote_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateInternalNoteDto" + } + } + } + }, + "responses": { + "201": { + "description": "Internal note added successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InternalNoteResponseDto" + } + } + } + }, + "403": { + "description": "Access denied - staff role required." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Add an internal note to a claim", + "tags": [ + "Onchain Proxy" + ] + }, + "get": { + "description": "Retrieves all internal notes for a specific claim.", + "operationId": "ClaimsController_getNotes_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Internal notes retrieved successfully.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InternalNoteResponseDto" + } + } + } + } + }, + "403": { + "description": "Access denied - staff role required." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "List internal notes for a claim", + "tags": [ + "Onchain Proxy" + ] + } + }, + "/api/v1/claims/{id}/cancel": { + "post": { + "description": "Cancels an active claim (requested / verified / approved). Releases the locked budget back to the campaign and records a full audit trail. Disbursed claims cannot be cancelled.", + "operationId": "ClaimsController_cancel_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CancelClaimDto" + } + } + } + }, + "responses": { + "200": { + "description": "Claim cancelled successfully." + }, + "400": { + "description": "Claim is already cancelled or in a non-cancellable status." + }, + "403": { + "description": "Access denied - operator role required." + }, + "404": { + "description": "Claim not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Cancel a claim", + "tags": [ + "Onchain Proxy" + ] + } + }, + "/api/v1/claims/{id}/reissue": { + "post": { + "description": "Atomically cancels the original claim and creates a replacement. The replacement is linked to the original via `reissuedFromId`, preserving the full audit chain. Locked balances are transferred to the new claim — no double-counting occurs. Returns both the cancelled original and the new replacement.", + "operationId": "ClaimsController_reissue_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReissueClaimDto" + } + } + } + }, + "responses": { + "201": { + "description": "Original claim cancelled and replacement created.", + "content": { + "application/json": { + "schema": { + "properties": { + "original": { + "type": "object", + "description": "The cancelled original claim." + }, + "replacement": { + "type": "object", + "description": "The newly created replacement claim." + } + } + } + } + } + }, + "400": { + "description": "Original claim is not in a cancellable status." + }, + "403": { + "description": "Access denied - operator role required." + }, + "404": { + "description": "Original claim not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Cancel and reissue a claim", + "tags": [ + "Onchain Proxy" + ] + } + }, + "/api/v1/claims/{id}/reissue-history": { + "get": { + "description": "Returns the full lineage of a claim — the original and every replacement — ordered from oldest to newest. Pass any claim ID in the chain to retrieve the complete history.", + "operationId": "ClaimsController_getReissueHistory_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Reissue chain retrieved successfully.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object" + } + } + } + } + }, + "403": { + "description": "Access denied - operator role required." + }, + "404": { + "description": "Claim not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get reissue chain for a claim", + "tags": [ + "Onchain Proxy" + ] + } + }, + "/api/v1/claims/export": { + "get": { + "description": "Exports claim records as CSV with support for date range, status, organization, token, and pagination filters. Excludes sensitive recipient data (recipientRef is encrypted and not exported).", + "operationId": "ClaimsController_exportClaims_v1", + "parameters": [ + { + "name": "limit", + "required": false, + "in": "query", + "description": "Items per page (default: 50, max: 200)", + "schema": {} + }, + { + "name": "page", + "required": false, + "in": "query", + "description": "Page number (default: 1)", + "schema": {} + }, + { + "name": "tokenAddress", + "required": false, + "in": "query", + "description": "Token address filter", + "schema": {} + }, + { + "name": "orgId", + "required": false, + "in": "query", + "description": "Organization ID filter", + "schema": {} + }, + { + "name": "campaignId", + "required": false, + "in": "query", + "description": "Campaign ID filter", + "schema": {} + }, + { + "name": "status", + "required": false, + "in": "query", + "description": "Claim status filter", + "schema": {} + }, + { + "name": "to", + "required": false, + "in": "query", + "description": "End date (ISO string)", + "schema": {} + }, + { + "name": "from", + "required": false, + "in": "query", + "description": "Start date (ISO string)", + "schema": {} + } + ], + "responses": { + "200": { + "description": "Claims exported successfully.", + "content": { + "text/csv": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Missing or invalid authentication credentials." + }, + "403": { + "description": "Access denied - operator or admin role required." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Export claims as CSV", + "tags": [ + "Onchain Proxy" + ] + } + }, + "/api/v1/analytics/global-stats": { + "get": { + "description": "Returns aggregated totals and breakdowns by token and region for the dashboard.", + "operationId": "AnalyticsController_getGlobalStats_v1", + "parameters": [ + { + "name": "from", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "to", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "region", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "token", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Global statistics retrieved successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GlobalStatsDto" + } + } + } + } + }, + "summary": "Get global distribution statistics", + "tags": [ + "Analytics" + ] + } + }, + "/api/v1/analytics/map-data": { + "get": { + "description": "Returns a list of distribution points with coordinates and amounts for map visualization.", + "operationId": "AnalyticsController_getMapData_v1", + "parameters": [ + { + "name": "region", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "token", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Map data points retrieved successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MapDataDto" + } + } + } + } + }, + "summary": "Get map data points", + "tags": [ + "Analytics" + ] + } + }, + "/api/v1/analytics/map-anonymized": { + "get": { + "description": "Returns distribution data in GeoJSON format with anonymized locations for privacy.", + "operationId": "AnalyticsController_getMapAnonymizedData_v1", + "parameters": [ + { + "name": "region", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "token", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "status", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Anonymized GeoJSON data retrieved successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GeoJsonFeatureCollection" + } + } + } + } + }, + "summary": "Get anonymized map data (GeoJSON)", + "tags": [ + "Analytics" + ] + } + }, + "/api/v1/onchain/aid-escrow/packages": { + "post": { + "description": "Creates a new aid package with specified recipient, amount, and expiration. Only authorized operators can create packages.", + "operationId": "AidEscrowController_createAidPackage_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateAidPackageDto" + } + } + } + }, + "responses": { + "201": { + "description": "Package created successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "packageId": "pkg_123456789", + "transactionHash": "ABC123DEF456ABC123DEF456ABC123DEF456ABC123DEF456ABC123DEF456ABCD", + "timestamp": "2026-03-30T12:30:00.000Z", + "status": "success", + "metadata": { + "contractId": "CBAA...", + "operator": "GBUQWP3BOUZX34ULNQG23RQ6F4BFXWBTRSE53XSTE23JMCVOCJGXVSVZ" + } + } + } + } + } + }, + "400": { + "description": "Invalid input parameters." + }, + "500": { + "description": "Blockchain transaction failed." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Create an aid package", + "tags": [ + "Onchain - Aid Escrow" + ] + } + }, + "/api/v1/onchain/aid-escrow/packages/batch": { + "post": { + "description": "Creates multiple aid packages for multiple recipients in a single transaction. More efficient than individual creation.", + "operationId": "AidEscrowController_batchCreateAidPackages_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BatchCreateAidPackagesDto" + } + } + } + }, + "responses": { + "201": { + "description": "Packages created successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "packageIds": [ + "0", + "1", + "2" + ], + "transactionHash": "ABC123DEF456ABC123DEF456ABC123DEF456ABC123DEF456ABC123DEF456ABCD", + "timestamp": "2026-03-30T12:30:00.000Z", + "status": "success", + "metadata": { + "contractId": "CBAA...", + "count": 3 + } + } + } + } + } + }, + "400": { + "description": "Invalid input or mismatched arrays." + }, + "500": { + "description": "Blockchain transaction failed." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Batch create aid packages", + "tags": [ + "Onchain - Aid Escrow" + ] + } + }, + "/api/v1/onchain/aid-escrow/packages/{id}/claim": { + "post": { + "description": "Claims an aid package as the recipient, transferring the funds to their wallet. Can only be claimed once.", + "operationId": "AidEscrowController_claimAidPackage_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Package claimed successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "packageId": "pkg_123456789", + "transactionHash": "ABC123DEF456ABC123DEF456ABC123DEF456ABC123DEF456ABC123DEF456ABCD", + "timestamp": "2026-03-30T12:30:00.000Z", + "status": "success", + "amountClaimed": "1000000000", + "metadata": { + "contractId": "CBAA...", + "recipient": "GBUQWP3BOUZX34ULNQG23RQ6F4BFXWBTRSE53XSTE23JMCVOCJGXVSVZ" + } + } + } + } + } + }, + "400": { + "description": "Package not found or not claimable." + }, + "404": { + "description": "Package does not exist." + }, + "500": { + "description": "Blockchain transaction failed." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Claim an aid package", + "tags": [ + "Onchain - Aid Escrow" + ] + } + }, + "/api/v1/onchain/aid-escrow/packages/{id}/disburse": { + "post": { + "description": "Disburses an aid package from the admin/operator, transferring funds to the recipient. Admin-only action.", + "operationId": "AidEscrowController_disburseAidPackage_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Package disbursed successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "packageId": "pkg_123456789", + "transactionHash": "ABC123DEF456ABC123DEF456ABC123DEF456ABC123DEF456ABC123DEF456ABCD", + "timestamp": "2026-03-30T12:30:00.000Z", + "status": "success", + "amountDisbursed": "1000000000", + "metadata": { + "contractId": "CBAA...", + "operator": "GBUQWP3BOUZX34ULNQG23RQ6F4BFXWBTRSE53XSTE23JMCVOCJGXVSVZ" + } + } + } + } + } + }, + "400": { + "description": "Package not found or not disbursable." + }, + "404": { + "description": "Package does not exist." + }, + "500": { + "description": "Blockchain transaction failed." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Disburse an aid package", + "tags": [ + "Onchain - Aid Escrow" + ] + } + }, + "/api/v1/onchain/aid-escrow/packages/{id}": { + "get": { + "description": "Retrieves the full details of an aid package including status, amount, and expiration.", + "operationId": "AidEscrowController_getAidPackage_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Package details retrieved successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "package": { + "id": "pkg_123456789", + "recipient": "GBUQWP3BOUZX34ULNQG23RQ6F4BFXWBTRSE53XSTE23JMCVOCJGXVSVZ", + "amount": "1000000000", + "token": "GATEMHCCKCY67ZUCKTROYN24ZYT5GK4EQZ5LKG3FZTSZ3NYNEJBBENSN", + "status": "Created", + "createdAt": 1711814400, + "expiresAt": 1714406400, + "metadata": { + "campaign_ref": "campaign-123" + } + }, + "timestamp": "2026-03-30T12:30:00.000Z" + } + } + } + } + }, + "404": { + "description": "Package not found." + }, + "500": { + "description": "Failed to retrieve package." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get aid package details", + "tags": [ + "Onchain - Aid Escrow" + ] + } + }, + "/api/v1/onchain/aid-escrow/stats": { + "get": { + "description": "Retrieves aggregated statistics for aid packages by token, including total committed, claimed, and expired amounts.", + "operationId": "AidEscrowController_getAidPackageStats_v1", + "parameters": [], + "responses": { + "200": { + "description": "Statistics retrieved successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "aggregates": { + "totalCommitted": "5000000000", + "totalClaimed": "2000000000", + "totalExpiredCancelled": "500000000" + }, + "timestamp": "2026-03-30T12:30:00.000Z" + } + } + } + } + }, + "400": { + "description": "Invalid token address." + }, + "500": { + "description": "Failed to retrieve statistics." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get aid package statistics", + "tags": [ + "Onchain - Aid Escrow" + ] + } + }, + "/api/v1/onchain/aid-escrow/transactions/{hash}/status": { + "get": { + "description": "Polls Soroban RPC for the status of a transaction by its hash. Returns a normalized status: pending, succeeded, failed, or unknown.", + "operationId": "AidEscrowController_getTransactionStatus_v1", + "parameters": [ + { + "name": "hash", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Transaction status retrieved successfully.", + "content": { + "application/json": { + "schema": { + "example": { + "hash": "ABC123DEF456ABC123DEF456ABC123DEF456ABC123DEF456ABC123DEF456ABCD", + "status": "succeeded", + "timestamp": "2026-03-30T12:30:00.000Z", + "ledger": 12345 + } + } + } + } + }, + "400": { + "description": "Invalid transaction hash." + }, + "404": { + "description": "Transaction not found." + }, + "500": { + "description": "Failed to retrieve transaction status." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get transaction status", + "tags": [ + "Onchain - Aid Escrow" + ] + } + }, + "/api/v1/api-keys": { + "post": { + "description": "Creates a new API key. The raw key is only returned at creation time; future listings show masked previews only.", + "operationId": "ApiKeysController_create_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateApiKeyDto" + } + } + } + }, + "responses": { + "201": { + "description": "API key created." + }, + "400": { + "description": "Invalid payload." + }, + "401": { + "description": "Missing or invalid credentials." + }, + "403": { + "description": "Insufficient permissions." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Create an API key (returned once)", + "tags": [ + "API Keys" + ] + }, + "get": { + "operationId": "ApiKeysController_list_v1", + "parameters": [], + "responses": { + "200": { + "description": "API keys listed." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "List API keys (masked previews only)", + "tags": [ + "API Keys" + ] + } + }, + "/api/v1/api-keys/{id}/rotate": { + "post": { + "operationId": "ApiKeysController_rotate_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "API key rotated." + }, + "400": { + "description": "Cannot rotate revoked key." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Rotate an API key (revoke old, create new)", + "tags": [ + "API Keys" + ] + } + }, + "/api/v1/api-keys/{id}/revoke": { + "post": { + "operationId": "ApiKeysController_revoke_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RevokeApiKeyDto" + } + } + } + }, + "responses": { + "200": { + "description": "API key revoked." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Revoke an API key", + "tags": [ + "API Keys" + ] + } + }, + "/api/v1/sessions": { + "post": { + "description": "Create a new verification session with optional multi-step flow definition", + "operationId": "SessionController_createSession_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSessionDto" + } + } + } + }, + "responses": { + "201": { + "description": "Session created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionResponseDto" + } + } + } + } + }, + "summary": "Create a new session", + "tags": [ + "sessions" + ] + }, + "get": { + "description": "Retrieve sessions filtered by context ID", + "operationId": "SessionController_getSessions_v1", + "parameters": [ + { + "name": "contextId", + "required": false, + "in": "query", + "description": "Context ID to filter sessions", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Sessions retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionResponseDto" + } + } + } + } + } + }, + "summary": "Get sessions by context", + "tags": [ + "sessions" + ] + } + }, + "/api/v1/sessions/{id}": { + "get": { + "description": "Retrieve session details including steps and current status", + "operationId": "SessionController_getSession_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Session ID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Session retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionResponseDto" + } + } + } + } + }, + "summary": "Get session by ID", + "tags": [ + "sessions" + ] + } + }, + "/api/v1/sessions/{sessionId}/steps/{stepId}/submit": { + "post": { + "description": "Submit data to a specific step with idempotent handling using submission key", + "operationId": "SessionController_submitToStep_v1", + "parameters": [ + { + "name": "sessionId", + "required": true, + "in": "path", + "description": "Session ID", + "schema": { + "type": "string" + } + }, + { + "name": "stepId", + "required": true, + "in": "path", + "description": "Step ID", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubmitStepDto" + } + } + } + }, + "responses": { + "200": { + "description": "Step submission processed successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubmissionResponseDto" + } + } + } + } + }, + "summary": "Submit data to a session step", + "tags": [ + "sessions" + ] + } + }, + "/api/v1/sessions/{id}/resume": { + "post": { + "description": "Resume an expired or paused session", + "operationId": "SessionController_resumeSession_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Session ID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Session resumed successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionResponseDto" + } + } + } + } + }, + "summary": "Resume a session", + "tags": [ + "sessions" + ] + } + }, + "/api/v1/evidence/upload": { + "post": { + "description": "Encrypts and stores a single evidence file locally for eventual upload. Accepts one file (max 10MB) in the \"file\" field. Allowed types: image/jpeg, image/png, image/gif, application/pdf, text/plain.", + "operationId": "EvidenceController_upload_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "required": [ + "file" + ], + "properties": { + "file": { + "type": "string", + "format": "binary" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "Evidence queued successfully." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Upload evidence to queue", + "tags": [ + "Evidence Queue" + ] + } + }, + "/api/v1/evidence/queue": { + "get": { + "description": "Retrieves all evidence items in the queue for the current user.", + "operationId": "EvidenceController_getQueue_v1", + "parameters": [], + "responses": { + "200": { + "description": "Queue retrieved successfully." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "List evidence queue", + "tags": [ + "Evidence Queue" + ] + } + }, + "/api/v1/evidence/queue/{id}/retry": { + "post": { + "description": "Manually triggers a retry for a failed evidence upload.", + "operationId": "EvidenceController_retry_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Retry initiated." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Retry evidence upload", + "tags": [ + "Evidence Queue" + ] + } + }, + "/api/v1/evidence/queue/{id}": { + "delete": { + "description": "Removes an evidence item from the queue and deletes the local file.", + "operationId": "EvidenceController_remove_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Item removed successfully." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Remove from queue", + "tags": [ + "Evidence Queue" + ] + } + }, + "/api/v1/evidence/upload-sessions": { + "post": { + "operationId": "UploadSessionController_create_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateUploadSessionDto" + } + } + } + }, + "responses": { + "201": { + "description": "Session created." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Create a chunked upload session", + "tags": [ + "Evidence Upload Sessions" + ] + } + }, + "/api/v1/evidence/upload-sessions/{id}/chunks": { + "post": { + "operationId": "UploadSessionController_uploadChunk_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/UploadChunkDto" + } + } + } + }, + "responses": { + "200": { + "description": "Chunk received." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Upload a single chunk", + "tags": [ + "Evidence Upload Sessions" + ] + } + }, + "/api/v1/evidence/upload-sessions/{id}/finalize": { + "post": { + "operationId": "UploadSessionController_finalize_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Evidence queued." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Finalize session and assemble evidence file", + "tags": [ + "Evidence Upload Sessions" + ] + } + }, + "/api/v1/evidence/upload-sessions/{id}/status": { + "get": { + "operationId": "UploadSessionController_status_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Session status." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get received chunks (for resume)", + "tags": [ + "Evidence Upload Sessions" + ] + } + }, + "/api/v1/retention-policy": { + "post": { + "description": "Defines a retention window and purge strategy for a specific entity type.", + "operationId": "RetentionPolicyController_create_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateRetentionPolicyDto" + } + } + } + }, + "responses": { + "201": { + "description": "" + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Create a retention policy", + "tags": [ + "Retention Policy" + ] + }, + "get": { + "description": "Returns all configured retention policies, ordered by entity.", + "operationId": "RetentionPolicyController_findAll_v1", + "parameters": [ + { + "name": "entity", + "required": false, + "in": "query", + "description": "Filter by entity name", + "schema": {} + } + ], + "responses": { + "200": { + "description": "" + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "List all retention policies", + "tags": [ + "Retention Policy" + ] + } + }, + "/api/v1/retention-policy/entities": { + "get": { + "description": "Returns the list of entity types that support retention policies.", + "operationId": "RetentionPolicyController_getSupportedEntities_v1", + "parameters": [], + "responses": { + "200": { + "description": "" + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "List supported entity names", + "tags": [ + "Retention Policy" + ] + } + }, + "/api/v1/retention-policy/{id}": { + "get": { + "operationId": "RetentionPolicyController_findOne_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Retention policy ID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get a single retention policy", + "tags": [ + "Retention Policy" + ] + }, + "put": { + "description": "Partially update a retention policy. Changes take effect on the next purge run.", + "operationId": "RetentionPolicyController_update_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Retention policy ID", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateRetentionPolicyDto" + } + } + } + }, + "responses": { + "200": { + "description": "" + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Update a retention policy", + "tags": [ + "Retention Policy" + ] + }, + "delete": { + "description": "Removes a retention policy. The entity will no longer be purged automatically.", + "operationId": "RetentionPolicyController_remove_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "description": "Retention policy ID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Delete a retention policy", + "tags": [ + "Retention Policy" + ] + } + }, + "/api/v1/retention-policy/purge": { + "post": { + "description": "Manually trigger a retention purge for all enabled policies. Each purge produces an audit event recording the number of records affected.", + "operationId": "RetentionPolicyController_executePurge_v1", + "parameters": [], + "responses": { + "201": { + "description": "" + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Trigger a purge run", + "tags": [ + "Retention Policy" + ] + } + }, + "/api/v1/retention-policy/seed": { + "post": { + "description": "Creates default retention policies for all supported entities if they do not already exist.", + "operationId": "RetentionPolicyController_seedDefaults_v1", + "parameters": [], + "responses": { + "201": { + "description": "" + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Seed default retention policies", + "tags": [ + "Retention Policy" + ] + } + }, + "/api/v1/orgs/{id}/invites": { + "post": { + "operationId": "InvitesController_createInvite_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "" + } + }, + "tags": [ + "Invites" + ] + }, + "get": { + "operationId": "InvitesController_listInvites_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "tags": [ + "Invites" + ] + } + }, + "/api/v1/invites/{id}/accept": { + "post": { + "operationId": "InvitesController_acceptInvite_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "" + } + }, + "tags": [ + "Invites" + ] + } + }, + "/api/v1/invites/{id}": { + "delete": { + "operationId": "InvitesController_revokeInvite_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "tags": [ + "Invites" + ] + } + }, + "/api/v1/admin/search": { + "get": { + "operationId": "AdminSearchController_search_v1", + "parameters": [ + { + "name": "q", + "required": true, + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "entity", + "required": true, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "tags": [ + "AdminSearch" + ] + } + }, + "/api/v1/entity-linking/link": { + "post": { + "description": "Create a link between an extracted entity and a canonical registry record with confidence scoring", + "operationId": "EntityLinkingController_linkEntity_v1", + "parameters": [], + "responses": { + "201": { + "description": "" + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Link extracted entity to canonical registry", + "tags": [ + "Entity Linking" + ] + } + }, + "/api/v1/entity-linking/links": { + "get": { + "description": "Search and filter entity links by various criteria", + "operationId": "EntityLinkingController_queryLinks_v1", + "parameters": [ + { + "name": "limit", + "required": false, + "in": "query", + "schema": { + "type": "number" + } + }, + { + "name": "page", + "required": false, + "in": "query", + "schema": { + "type": "number" + } + }, + { + "name": "isActive", + "required": false, + "in": "query", + "schema": { + "type": "boolean" + } + }, + { + "name": "minConfidence", + "required": false, + "in": "query", + "schema": { + "type": "number" + } + }, + { + "name": "entityType", + "required": false, + "in": "query", + "schema": { + "enum": [ + "organization", + "location", + "asset", + "project" + ], + "type": "string" + } + }, + { + "name": "sourceId", + "required": false, + "in": "query", + "schema": {} + }, + { + "name": "sourceType", + "required": false, + "in": "query", + "schema": { + "enum": [ + "campaign", + "claim", + "verification" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Query entity links", + "tags": [ + "Entity Linking" + ] + } + }, + "/api/v1/entity-linking/campaign/{campaignId}": { + "get": { + "description": "Retrieve all entity links associated with a specific campaign", + "operationId": "EntityLinkingController_getLinksByCampaign_v1", + "parameters": [ + { + "name": "campaignId", + "required": true, + "in": "path", + "description": "Campaign ID", + "schema": { + "type": "string" + } + }, + { + "name": "entityType", + "required": false, + "in": "query", + "schema": { + "enum": [ + "organization", + "location", + "asset", + "project" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get entity links by campaign", + "tags": [ + "Entity Linking" + ] + } + }, + "/api/v1/entity-linking/claim/{claimId}": { + "get": { + "description": "Retrieve all entity links associated with a specific claim", + "operationId": "EntityLinkingController_getLinksByClaim_v1", + "parameters": [ + { + "name": "claimId", + "required": true, + "in": "path", + "description": "Claim ID", + "schema": { + "type": "string" + } + }, + { + "name": "entityType", + "required": false, + "in": "query", + "schema": { + "enum": [ + "organization", + "location", + "asset", + "project" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get entity links by claim", + "tags": [ + "Entity Linking" + ] + } + }, + "/api/v1/entity-linking/verification/{verificationId}": { + "get": { + "description": "Retrieve all entity links associated with a specific verification", + "operationId": "EntityLinkingController_getLinksByVerification_v1", + "parameters": [ + { + "name": "verificationId", + "required": true, + "in": "path", + "description": "Verification ID", + "schema": { + "type": "string" + } + }, + { + "name": "entityType", + "required": false, + "in": "query", + "schema": { + "enum": [ + "organization", + "location", + "asset", + "project" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get entity links by verification", + "tags": [ + "Entity Linking" + ] + } + }, + "/api/v1/entity-linking/review/{linkId}": { + "patch": { + "description": "Manually review and curate an entity link", + "operationId": "EntityLinkingController_reviewLink_v1", + "parameters": [ + { + "name": "linkId", + "required": true, + "in": "path", + "description": "Entity Link ID", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Review and update entity link", + "tags": [ + "Entity Linking" + ] + } + }, + "/api/v1/entity-linking/registry/search": { + "get": { + "description": "Search for potential matches in the canonical registry", + "operationId": "EntityLinkingController_searchRegistry_v1", + "parameters": [ + { + "name": "entityType", + "required": true, + "in": "query", + "schema": { + "enum": [ + "organization", + "location", + "asset", + "project" + ], + "type": "string" + } + }, + { + "name": "query", + "required": true, + "in": "query", + "description": "Search query", + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "required": false, + "in": "query", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Search canonical registry", + "tags": [ + "Entity Linking" + ] + } + }, + "/api/v1/deployment-metadata": { + "post": { + "description": "Creates a new contract deployment metadata record. Used to record contract deployments with their network, address, and provenance.", + "operationId": "DeploymentMetadataController_create_v1", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateDeploymentMetadataDto" + } + } + } + }, + "responses": { + "201": { + "description": "Deployment metadata created successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentMetadataResponseDto" + } + } + } + }, + "400": { + "description": "Invalid input parameters." + }, + "500": { + "description": "Failed to create deployment metadata." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Create deployment metadata (admin only)", + "tags": [ + "Deployment Metadata" + ] + }, + "get": { + "description": "Returns all contract deployment metadata records, ordered by deployment date (newest first).", + "operationId": "DeploymentMetadataController_findAll_v1", + "parameters": [], + "responses": { + "200": { + "description": "Deployment metadata records.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeploymentMetadataResponseDto" + } + } + } + } + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "List all deployment metadata (admin only)", + "tags": [ + "Deployment Metadata" + ] + } + }, + "/api/v1/deployment-metadata/by-network/{network}": { + "get": { + "description": "Returns all contract deployments for a specific network (e.g., testnet, mainnet).", + "operationId": "DeploymentMetadataController_findByNetwork_v1", + "parameters": [ + { + "name": "network", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Deployment metadata for the specified network.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeploymentMetadataResponseDto" + } + } + } + } + }, + "404": { + "description": "No deployments found for this network." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get deployment metadata by network (admin only)", + "tags": [ + "Deployment Metadata" + ] + } + }, + "/api/v1/deployment-metadata/by-contract/{network}/{contractName}": { + "get": { + "description": "Returns the latest deployment metadata for a specific contract on a specific network.", + "operationId": "DeploymentMetadataController_findByNetworkAndContractName_v1", + "parameters": [ + { + "name": "network", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + }, + { + "name": "contractName", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Deployment metadata for the specified contract.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentMetadataResponseDto" + } + } + } + }, + "404": { + "description": "Deployment metadata not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get deployment metadata by network and contract name (admin only)", + "tags": [ + "Deployment Metadata" + ] + } + }, + "/api/v1/deployment-metadata/by-contract-id/{contractId}": { + "get": { + "description": "Returns deployment metadata for a specific contract ID (address).", + "operationId": "DeploymentMetadataController_findByContractId_v1", + "parameters": [ + { + "name": "contractId", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Deployment metadata for the specified contract ID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentMetadataResponseDto" + } + } + } + }, + "404": { + "description": "Deployment metadata not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Get deployment metadata by contract ID (admin only)", + "tags": [ + "Deployment Metadata" + ] + } + }, + "/api/v1/deployment-metadata/{id}": { + "put": { + "description": "Updates an existing deployment metadata record.", + "operationId": "DeploymentMetadataController_update_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateDeploymentMetadataDto" + } + } + } + }, + "responses": { + "200": { + "description": "Deployment metadata updated successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeploymentMetadataResponseDto" + } + } + } + }, + "400": { + "description": "Invalid input parameters." + }, + "404": { + "description": "Deployment metadata not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Update deployment metadata (admin only)", + "tags": [ + "Deployment Metadata" + ] + }, + "delete": { + "description": "Deletes a deployment metadata record.", + "operationId": "DeploymentMetadataController_delete_v1", + "parameters": [ + { + "name": "id", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "404": { + "description": "Deployment metadata not found." + } + }, + "security": [ + { + "JWT-auth": [] + } + ], + "summary": "Delete deployment metadata (admin only)", + "tags": [ + "Deployment Metadata" + ] + } + }, + "/api/v1/admin/sandbox/seed/tenant": { + "post": { + "operationId": "SandboxController_seedTenant_v1", + "parameters": [], + "responses": { + "201": { + "description": "" + } + }, + "tags": [ + "Sandbox" + ] + } + }, + "/api/v1/admin/sandbox/seed/campaigns": { + "post": { + "operationId": "SandboxController_seedCampaigns_v1", + "parameters": [], + "responses": { + "201": { + "description": "" + } + }, + "tags": [ + "Sandbox" + ] + } + }, + "/api/v1/admin/sandbox/seed/claims": { + "post": { + "operationId": "SandboxController_seedClaims_v1", + "parameters": [], + "responses": { + "201": { + "description": "" + } + }, + "tags": [ + "Sandbox" + ] + } + }, + "/api/v1/admin/sandbox/seed": { + "post": { + "operationId": "SandboxController_seedAll_v1", + "parameters": [], + "responses": { + "201": { + "description": "" + } + }, + "tags": [ + "Sandbox" + ] + }, + "delete": { + "operationId": "SandboxController_resetSeed_v1", + "parameters": [], + "responses": { + "200": { + "description": "" + } + }, + "tags": [ + "Sandbox" + ] + } + } + }, + "info": { + "title": "ChainForge API", + "description": "API documentation for ChainForge platform - Humanitarian aid and verification system\n\n## API Versioning\n\nThis API uses URI-based versioning. The current version is **v1**.\n\n### Version Format\nAll endpoints are prefixed with the version number: `/api/v1/...`\n\n### Supported Versions\n| Version | Status | Description |\n|---------|--------|-------------|\n| v1 | Current | Active version with full support |\n\n### Deprecation Policy\n- Deprecated endpoints will be marked with `@Deprecated` in the documentation\n- Deprecated versions will be supported for at least 6 months after deprecation notice\n- Clients will receive deprecation warnings via the `Sunset` HTTP header\n- Migration guides will be provided for major version changes\n\n### Future Versions\nWhen new versions are released:\n- New endpoints will be available at `/api/v2/...`, etc.\n- Previous versions remain accessible during the deprecation period\n- Clients should monitor the API documentation for version updates", + "version": "1.0", + "contact": {} + }, + "tags": [], + "servers": [ + { + "url": "http://localhost:3000", + "description": "Local Development" + }, + { + "url": "https://api.chainforge.app", + "description": "Staging" + }, + { + "url": "https://api.chainforge.app", + "description": "Production" + } + ], + "components": { + "securitySchemes": { + "JWT-auth": { + "scheme": "bearer", + "bearerFormat": "JWT", + "type": "http", + "name": "Authorization", + "in": "header", + "description": "Enter JWT token" + }, + "api-key": { + "type": "apiKey", + "in": "header", + "name": "x-api-key", + "description": "API key for external access" + } + }, + "schemas": { + "AiTaskWebhookDto": { + "type": "object", + "properties": { + "taskId": { + "type": "string", + "description": "The ID of the task", + "example": "task-123-abc" + }, + "deliveryId": { + "type": "string", + "description": "Unique delivery ID to prevent duplicate processing", + "example": "del_12345abcde" + }, + "timestamp": { + "type": "string", + "description": "Timestamp of the event generation for state ordering", + "example": "2024-03-24T10:30:00Z" + }, + "status": { + "type": "string", + "description": "Status of the task", + "enum": [ + "pending", + "processing", + "completed", + "failed" + ], + "example": "completed" + }, + "result": { + "type": "object", + "description": "Result of the task execution", + "example": { + "prediction": "approved", + "confidence": 0.95 + } + }, + "error": { + "type": "string", + "description": "Error message if task failed", + "example": "Image processing failed: invalid format" + }, + "taskType": { + "type": "string", + "description": "Type of the task", + "example": "image_analysis" + }, + "completedAt": { + "type": "string", + "description": "Timestamp when the task completed", + "example": "2024-03-24T10:30:00Z" + } + }, + "required": [ + "taskId", + "deliveryId", + "timestamp", + "status" + ] + }, + "StartVerificationDto": { + "type": "object", + "properties": { + "channel": { + "type": "string", + "description": "Verification channel: email or phone", + "enum": [ + "email", + "phone" + ], + "example": "email" + }, + "email": { + "type": "string", + "description": "Email address (required when channel is email)", + "example": "user@example.com" + }, + "phone": { + "type": "string", + "description": "Phone number (required when channel is phone)", + "example": "+15551234567" + } + }, + "required": [ + "channel" + ] + }, + "ResendVerificationDto": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Verification session ID returned from start", + "example": "clv789xyz123" + } + }, + "required": [ + "sessionId" + ] + }, + "CompleteVerificationDto": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Unique identifier for the current verification session.", + "example": "ses_123abc456def" + }, + "code": { + "type": "string", + "description": "OTP code received via email or phone", + "example": "123456", + "minLength": 4, + "maxLength": 8 + } + }, + "required": [ + "sessionId", + "code" + ] + }, + "CreateVerificationDto": { + "type": "object", + "properties": { + "userId": { + "type": "string", + "description": "User submitting the verification", + "example": "clu456def789" + }, + "documentType": { + "type": "string", + "description": "Document type being submitted", + "example": "NATIONAL_ID" + }, + "submittedAt": { + "format": "date-time", + "type": "string", + "description": "Timestamp when the verification request was submitted.", + "example": "2025-01-23T11:00:00.000Z" + } + }, + "required": [ + "userId", + "documentType" + ] + }, + "CreateInternalNoteDto": { + "type": "object", + "properties": { + "content": { + "type": "string", + "description": "The content of the internal note.", + "example": "Investigation shows that the recipient has provided valid evidence." + }, + "category": { + "type": "string", + "description": "Optional category for the note.", + "example": "investigation" + } + }, + "required": [ + "content" + ] + }, + "InternalNoteResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "clv789xyz123" + }, + "entityType": { + "type": "string", + "example": "claim" + }, + "entityId": { + "type": "string", + "example": "clv789xyz123" + }, + "content": { + "type": "string", + "example": "Investigation notes..." + }, + "authorId": { + "type": "string", + "example": "clv789xyz123" + }, + "category": { + "type": "object", + "example": "investigation", + "nullable": true + }, + "createdAt": { + "format": "date-time", + "type": "string", + "example": "2025-01-23T11:00:00.000Z" + }, + "updatedAt": { + "format": "date-time", + "type": "string", + "example": "2025-01-23T11:00:00.000Z" + } + }, + "required": [ + "id", + "entityType", + "entityId", + "content", + "authorId", + "createdAt", + "updatedAt" + ] + }, + "CampaignStatus": { + "type": "string", + "enum": [ + "draft", + "active", + "paused", + "completed", + "archived" + ], + "description": "Current status of the campaign." + }, + "CreateCampaignDto": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Campaign title/name.", + "example": "Winter Relief 2026" + }, + "budget": { + "type": "number", + "description": "Total budget allocated to the campaign.", + "example": 25000.5, + "minimum": 0 + }, + "metadata": { + "type": "object", + "description": "Arbitrary campaign metadata (e.g., region, location, target audience).", + "example": { + "region": "Lagos", + "partner": "NGO-A", + "notes": "Phase 1" + }, + "additionalProperties": true + }, + "status": { + "description": "Current status of the campaign.", + "example": "draft", + "allOf": [ + { + "$ref": "#/components/schemas/CampaignStatus" + } + ] + } + }, + "required": [ + "name", + "budget" + ] + }, + "UpdateCampaignDto": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Updated campaign title/name.", + "example": "Winter Relief 2026 - Extended" + }, + "budget": { + "type": "number", + "description": "Updated campaign budget.", + "example": 30000, + "minimum": 0 + }, + "metadata": { + "type": "object", + "description": "Updated campaign metadata.", + "example": { + "region": "Lagos", + "partner": "NGO-B" + }, + "additionalProperties": true + }, + "status": { + "description": "Updated campaign status.", + "example": "active", + "allOf": [ + { + "$ref": "#/components/schemas/CampaignStatus" + } + ] + } + } + }, + "CreateClaimDto": { + "type": "object", + "properties": { + "campaignId": { + "type": "string", + "description": "ID of the campaign this claim belongs to", + "example": "campaign-uuid" + }, + "amount": { + "type": "number", + "description": "Amount requested in the claim", + "example": 100.5, + "minimum": 0 + }, + "recipientRef": { + "type": "string", + "description": "Reference to the recipient", + "example": "recipient-123" + }, + "tokenAddress": { + "type": "string", + "description": "Stellar token address (asset issuer or contract ID) for the distribution", + "example": "GATEMHCCKCY67ZUCKTROYN24ZYT5GK4EQZ5LKG3FZTSZ3NYNEJBBENSN" + }, + "evidenceRef": { + "type": "string", + "description": "Reference or link to evidence supporting the claim (e.g., photo, document hash).", + "example": "evidence-456" + }, + "expiresAt": { + "format": "date-time", + "type": "string", + "description": "When the claim should automatically expire if it remains unprocessed.", + "example": "2026-05-31T23:59:59.000Z" + } + }, + "required": [ + "campaignId", + "amount", + "recipientRef", + "tokenAddress" + ] + }, + "ClaimReceiptDto": { + "type": "object", + "properties": { + "claimId": { + "type": "string", + "description": "Unique claim identifier", + "example": "claim-uuid-123" + }, + "packageId": { + "type": "string", + "description": "Campaign/package ID", + "example": "campaign-uuid-456" + }, + "status": { + "type": "string", + "description": "Current status of the claim", + "enum": [ + "requested", + "verified", + "approved", + "disbursed", + "archived", + "cancelled" + ], + "example": "disbursed" + }, + "amount": { + "type": "number", + "description": "Token amount for the claim", + "example": 100.5 + }, + "timestamp": { + "type": "string", + "description": "ISO timestamp of claim creation", + "example": "2024-01-15T10:30:00Z" + }, + "tokenAddress": { + "type": "string", + "description": "Stellar token address (optional)", + "example": "GATEMHCCKCY67ZUCKTROYN24ZYT5GK4EQZ5LKG3FZTSZ3NYNEJBBENSN" + }, + "recipientRef": { + "type": "string", + "description": "Recipient reference (optional)", + "example": "recipient-ref-789" + } + }, + "required": [ + "claimId", + "packageId", + "status", + "amount", + "timestamp" + ] + }, + "SendReceiptShareDto": { + "type": "object", + "properties": { + "emailAddresses": { + "description": "Email address(es) to send receipt to", + "example": [ + "recipient@example.com" + ], + "type": "array", + "items": { + "type": "array" + } + }, + "phoneNumbers": { + "description": "Phone number(s) to send receipt to (SMS)", + "example": [ + "+1234567890" + ], + "type": "array", + "items": { + "type": "array" + } + }, + "channel": { + "type": "string", + "description": "Channel for sharing", + "enum": [ + "email", + "sms", + "inline" + ], + "example": "email" + }, + "message": { + "type": "string", + "description": "Custom message to include with receipt (optional)" + } + }, + "required": [ + "emailAddresses", + "phoneNumbers", + "channel" + ] + }, + "ClaimShareResponseDto": { + "type": "object", + "properties": { + "receiptData": { + "type": "string", + "description": "Base64-encoded receipt image or data" + }, + "mimeType": { + "type": "string", + "description": "MIME type of the receipt data", + "example": "text/plain" + }, + "filename": { + "type": "string", + "description": "Filename for download", + "example": "claim-receipt-uuid.txt" + }, + "text": { + "type": "string", + "description": "Text representation of receipt for sharing" + } + }, + "required": [ + "receiptData", + "mimeType", + "filename", + "text" + ] + }, + "CancelClaimDto": { + "type": "object", + "properties": { + "operatorId": { + "type": "string", + "description": "ID of the operator performing the cancellation.", + "example": "operator-uuid" + }, + "reason": { + "type": "string", + "description": "Human-readable reason for cancellation.", + "example": "Recipient relocated; package no longer applicable.", + "maxLength": 500 + } + }, + "required": [ + "operatorId" + ] + }, + "ReissueClaimDto": { + "type": "object", + "properties": { + "operatorId": { + "type": "string", + "description": "ID of the operator performing the reissue.", + "example": "operator-uuid" + }, + "amount": { + "type": "number", + "description": "Override amount for the replacement package. Defaults to the original amount when omitted.", + "example": 750, + "minimum": 0 + }, + "recipientRef": { + "type": "string", + "description": "Override recipient reference for the replacement package.", + "example": "recipient-ref-new" + }, + "reason": { + "type": "string", + "description": "Human-readable reason for the reissue.", + "example": "Corrected amount after field verification.", + "maxLength": 500 + } + }, + "required": [ + "operatorId" + ] + }, + "BreakdownEntry": { + "type": "object", + "properties": { + "label": { + "type": "string", + "example": "USDC" + }, + "totalAmount": { + "type": "number", + "example": 1500.5 + }, + "count": { + "type": "number", + "example": 45 + } + }, + "required": [ + "label", + "totalAmount", + "count" + ] + }, + "TimeframeBucket": { + "type": "object", + "properties": { + "date": { + "type": "string", + "example": "2026-03-01" + }, + "totalAmount": { + "type": "number", + "example": 500 + }, + "count": { + "type": "number", + "example": 10 + } + }, + "required": [ + "date", + "totalAmount", + "count" + ] + }, + "GlobalStatsDto": { + "type": "object", + "properties": { + "totalAidDisbursed": { + "type": "number", + "example": 250000 + }, + "totalRecipients": { + "type": "number", + "example": 1250 + }, + "activeCampaigns": { + "type": "number", + "example": 12 + }, + "byToken": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BreakdownEntry" + } + }, + "byRegion": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BreakdownEntry" + } + }, + "timeSeries": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TimeframeBucket" + } + }, + "computedAt": { + "type": "string", + "example": "2026-03-30T10:00:00Z" + } + }, + "required": [ + "totalAidDisbursed", + "totalRecipients", + "activeCampaigns", + "byToken", + "byRegion", + "timeSeries", + "computedAt" + ] + }, + "MapDataPoint": { + "type": "object", + "properties": { + "id": { + "type": "string", + "example": "pkg-123" + }, + "lat": { + "type": "number", + "example": 6.5244 + }, + "lng": { + "type": "number", + "example": 3.3792 + }, + "amount": { + "type": "number", + "example": 100 + }, + "token": { + "type": "string", + "example": "USDC" + }, + "status": { + "type": "string", + "example": "delivered" + }, + "region": { + "type": "string", + "example": "Lagos" + } + }, + "required": [ + "id", + "lat", + "lng", + "amount", + "token", + "status", + "region" + ] + }, + "MapDataDto": { + "type": "object", + "properties": { + "points": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MapDataPoint" + } + }, + "computedAt": { + "type": "string", + "example": "2026-03-30T10:00:00Z" + } + }, + "required": [ + "points", + "computedAt" + ] + }, + "GeoJsonFeature": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "Feature" + }, + "geometry": { + "type": "object", + "example": { + "type": "Point", + "coordinates": [ + 3.3792, + 6.5244 + ] + } + }, + "properties": { + "type": "object" + } + }, + "required": [ + "type", + "geometry", + "properties" + ] + }, + "GeoJsonFeatureCollection": { + "type": "object", + "properties": { + "type": { + "type": "string", + "example": "FeatureCollection" + }, + "features": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GeoJsonFeature" + } + }, + "computedAt": { + "type": "string", + "example": "2026-03-30T10:00:00Z" + } + }, + "required": [ + "type", + "features", + "computedAt" + ] + }, + "CreateAidPackageDto": { + "type": "object", + "properties": { + "packageId": { + "type": "string", + "description": "Unique identifier for the package", + "example": "pkg_123456789" + }, + "recipientAddress": { + "type": "string", + "description": "Stellar address of the aid recipient", + "example": "GBUQWP3BOUZX34ULNQG23RQ6F4BFXWBTRSE53XSTE23JMCVOCJGXVSVZ" + }, + "amount": { + "type": "string", + "description": "Amount in stroops (i128 as string to preserve precision)", + "example": "1000000000" + }, + "tokenAddress": { + "type": "string", + "description": "Stellar token address", + "example": "GATEMHCCKCY67ZUCKTROYN24ZYT5GK4EQZ5LKG3FZTSZ3NYNEJBBENSN" + }, + "expiresAt": { + "type": "number", + "description": "Unix timestamp when the package expires", + "example": 1704067200 + }, + "metadata": { + "type": "object", + "description": "Optional metadata as key-value pairs", + "example": { + "campaign_ref": "campaign-123", + "region": "LATAM" + } + } + }, + "required": [ + "packageId", + "recipientAddress", + "amount", + "tokenAddress", + "expiresAt" + ] + }, + "BatchCreateAidPackagesDto": { + "type": "object", + "properties": { + "recipientAddresses": { + "description": "Array of recipient Stellar addresses", + "example": [ + "GBUQWP3BOUZX34ULNQG23RQ6F4BFXWBTRSE53XSTE23JMCVOCJGXVSVZ", + "GA5ZSEJYB37JRC5AVCIA5MOP4GZ5DA47EL5QRUVLYEK2OOABEXVR5CV7" + ], + "type": "array", + "items": { + "type": "string" + } + }, + "amounts": { + "description": "Array of amounts (in stroops, as strings)", + "example": [ + "1000000000", + "500000000" + ], + "type": "array", + "items": { + "type": "string" + } + }, + "tokenAddress": { + "type": "string", + "description": "Stellar token address", + "example": "GATEMHCCKCY67ZUCKTROYN24ZYT5GK4EQZ5LKG3FZTSZ3NYNEJBBENSN" + }, + "expiresIn": { + "type": "number", + "description": "Duration in seconds from now until expiration", + "example": 2592000 + }, + "metadata": { + "type": "object", + "description": "Optional metadata as key-value pairs" + } + }, + "required": [ + "recipientAddresses", + "amounts", + "tokenAddress", + "expiresIn" + ] + }, + "CreateApiKeyDto": { + "type": "object", + "properties": { + "role": { + "type": "string", + "enum": [ + "admin", + "operator", + "client", + "ngo" + ], + "description": "Role associated with this API key.", + "example": "operator" + }, + "ngoId": { + "type": "string", + "description": "Optional NGO scope for this key (required for NGO role).", + "example": "ngo_123" + }, + "description": { + "type": "string", + "description": "Human-friendly description of the key purpose.", + "example": "Onchain worker (prod)" + } + }, + "required": [ + "role" + ] + }, + "RevokeApiKeyDto": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "description": "Optional reason for revocation.", + "example": "compromised" + } + } + }, + "SessionStepDefinitionDto": { + "type": "object", + "properties": { + "stepName": { + "type": "string", + "description": "Name of the step" + }, + "stepOrder": { + "type": "number", + "description": "Order of the step in the flow" + }, + "maxAttempts": { + "type": "number", + "description": "Maximum attempts allowed for this step" + }, + "input": { + "type": "object", + "description": "Initial input data for the step" + } + }, + "required": [ + "stepName", + "stepOrder" + ] + }, + "CreateSessionDto": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "otp_verification", + "claim_verification", + "multi_step_verification" + ], + "description": "Type of session to create" + }, + "contextId": { + "type": "string", + "description": "Context identifier (e.g., claim ID, user ID)" + }, + "metadata": { + "type": "object", + "description": "Additional metadata for the session" + }, + "expiresAt": { + "type": "string", + "description": "Session expiration time" + }, + "steps": { + "description": "Steps to create for multi-step sessions", + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionStepDefinitionDto" + } + } + }, + "required": [ + "type" + ] + }, + "SessionStepResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "stepName": { + "type": "string" + }, + "stepOrder": { + "type": "number" + }, + "status": { + "type": "string", + "enum": [ + "pending", + "in_progress", + "completed", + "failed", + "skipped" + ] + }, + "input": { + "type": "object" + }, + "output": { + "type": "object" + }, + "error": { + "type": "string" + }, + "attempts": { + "type": "number" + }, + "maxAttempts": { + "type": "number" + }, + "startedAt": { + "format": "date-time", + "type": "string" + }, + "completedAt": { + "format": "date-time", + "type": "string" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "updatedAt": { + "format": "date-time", + "type": "string" + } + }, + "required": [ + "id", + "stepName", + "stepOrder", + "status", + "attempts", + "maxAttempts", + "createdAt", + "updatedAt" + ] + }, + "SessionResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "otp_verification", + "claim_verification", + "multi_step_verification" + ] + }, + "status": { + "type": "string", + "enum": [ + "pending", + "completed", + "expired", + "failed" + ] + }, + "contextId": { + "type": "string" + }, + "metadata": { + "type": "object" + }, + "expiresAt": { + "format": "date-time", + "type": "string" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "updatedAt": { + "format": "date-time", + "type": "string" + }, + "completedAt": { + "format": "date-time", + "type": "string" + }, + "failedAt": { + "format": "date-time", + "type": "string" + }, + "steps": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionStepResponseDto" + } + }, + "currentStep": { + "$ref": "#/components/schemas/SessionStepResponseDto" + }, + "nextStep": { + "$ref": "#/components/schemas/SessionStepResponseDto" + } + }, + "required": [ + "id", + "type", + "status", + "createdAt", + "updatedAt" + ] + }, + "SubmitStepDto": { + "type": "object", + "properties": { + "submissionKey": { + "type": "string", + "description": "Unique key for idempotent submission" + }, + "payload": { + "type": "object", + "description": "Step input data" + }, + "stepName": { + "type": "string", + "description": "Optional step name to target specific step" + } + }, + "required": [ + "submissionKey", + "payload" + ] + }, + "SubmissionResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "sessionId": { + "type": "string" + }, + "stepId": { + "type": "string" + }, + "submissionKey": { + "type": "string" + }, + "payload": { + "type": "object" + }, + "response": { + "type": "object" + }, + "createdAt": { + "format": "date-time", + "type": "string" + }, + "isIdempotent": { + "type": "boolean" + } + }, + "required": [ + "id", + "sessionId", + "submissionKey", + "payload", + "createdAt", + "isIdempotent" + ] + }, + "CreateUploadSessionDto": { + "type": "object", + "properties": {} + }, + "UploadChunkDto": { + "type": "object", + "properties": {} + }, + "CreateRetentionPolicyDto": { + "type": "object", + "properties": { + "entity": { + "type": "string", + "description": "Entity type this policy applies to (e.g. AuditLog, VerificationSession, Session, Claim)", + "example": "AuditLog" + }, + "retentionDays": { + "type": "number", + "description": "Number of days to retain records before purging", + "example": 90 + }, + "strategy": { + "type": "string", + "description": "Purge strategy: soft_delete, hard_delete, or anonymize", + "enum": [ + "soft_delete", + "hard_delete", + "anonymize" + ], + "default": "soft_delete" + }, + "enabled": { + "type": "boolean", + "description": "Whether the policy is active", + "default": true + }, + "description": { + "type": "string", + "description": "Human-readable description of the policy" + } + }, + "required": [ + "entity", + "retentionDays" + ] + }, + "UpdateRetentionPolicyDto": { + "type": "object", + "properties": { + "entity": { + "type": "string", + "description": "Entity type this policy applies to (e.g. AuditLog, VerificationSession, Session, Claim)", + "example": "AuditLog" + }, + "retentionDays": { + "type": "number", + "description": "Number of days to retain records before purging", + "example": 90 + }, + "strategy": { + "type": "string", + "description": "Purge strategy: soft_delete, hard_delete, or anonymize", + "enum": [ + "soft_delete", + "hard_delete", + "anonymize" + ], + "default": "soft_delete" + }, + "enabled": { + "type": "boolean", + "description": "Whether the policy is active", + "default": true + }, + "description": { + "type": "string", + "description": "Human-readable description of the policy" + } + } + }, + "CreateDeploymentMetadataDto": { + "type": "object", + "properties": {} + }, + "DeploymentMetadataResponseDto": { + "type": "object", + "properties": {} + }, + "UpdateDeploymentMetadataDto": { + "type": "object", + "properties": {} + } + } + } +} \ No newline at end of file diff --git a/app/frontend/package.json b/app/frontend/package.json index 178645ef..8e3cb394 100644 --- a/app/frontend/package.json +++ b/app/frontend/package.json @@ -8,10 +8,12 @@ "start": "next start", "lint": "eslint", "test": "jest", - "type-check": "tsc --noEmit" + "type-check": "tsc --noEmit", + "generate:api": "openapi-typescript openapi.json -o src/lib/generated/api.ts" }, "dependencies": { "@heroicons/react": "^2.2.0", + "openapi-fetch": "^0.13.5", "@radix-ui/react-avatar": "^1.1.11", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", @@ -36,6 +38,7 @@ }, "devDependencies": { "@tailwindcss/postcss": "^4", + "openapi-typescript": "^7.6.1", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.2.0", "@types/jest": "^30.0.0", diff --git a/app/frontend/src/components/dashboard/AidDistributionMap.tsx b/app/frontend/src/components/dashboard/AidDistributionMap.tsx index 1531fcbe..ca0949ff 100644 --- a/app/frontend/src/components/dashboard/AidDistributionMap.tsx +++ b/app/frontend/src/components/dashboard/AidDistributionMap.tsx @@ -4,12 +4,11 @@ import React, { useEffect, useMemo, useState } from 'react'; import Link from 'next/link'; import { MapContainer, Marker, Popup, TileLayer, useMapEvents } from 'react-leaflet'; import L from 'leaflet'; -import { fetchClient } from '@/lib/mock-api/client'; +import { apiClient } from '@/lib/api-client'; import { getAppUserRole, isOperationsRole } from '@/lib/app-role'; const DEFAULT_CENTER: [number, number] = [20, 0]; const DEFAULT_ZOOM = 2; -const API_URL = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:4000'; const STATUS_STYLES: Record = { delivered: 'aid-marker--delivered', @@ -144,16 +143,18 @@ export default function AidDistributionMap() { async function loadData() { try { setLoading(true); - const response = await fetchClient(`${API_URL}/analytics/map-data`); - if (!response.ok) { - throw new Error(`Request failed: ${response.status}`); + const { data: payload, error } = await apiClient.GET('/api/v1/analytics/map-data'); + if (error) { + throw new Error(`Request failed`); } - const payload: unknown = await response.json(); - const rawPoints = Array.isArray(payload) - ? payload - : payload && typeof payload === 'object' && Array.isArray((payload as { data?: unknown }).data) - ? (payload as { data: unknown[] }).data - : []; + const responseBody = payload as unknown; + const rawPoints = Array.isArray(responseBody) + ? responseBody + : responseBody && typeof responseBody === 'object' && Array.isArray((responseBody as Record).points) + ? (responseBody as { points: unknown[] }).points + : responseBody && typeof responseBody === 'object' && Array.isArray((responseBody as Record).data) + ? (responseBody as { data: unknown[] }).data + : []; const normalized = rawPoints .map(normalizePoint) .filter((item): item is AidPackagePoint => Boolean(item)); diff --git a/app/frontend/src/hooks/useCampaigns.ts b/app/frontend/src/hooks/useCampaigns.ts index c197c3a5..09dce4ab 100644 --- a/app/frontend/src/hooks/useCampaigns.ts +++ b/app/frontend/src/hooks/useCampaigns.ts @@ -1,7 +1,7 @@ 'use client'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; -import { fetchClient } from '@/lib/mock-api/client'; +import { apiClient } from '@/lib/api-client'; import type { Campaign, CampaignCreatePayload, @@ -9,67 +9,39 @@ import type { } from '@/types/campaign'; import { useActivity } from './useActivity'; -const API_URL = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:4000'; - -interface ApiResponse { - success: boolean; - message?: string; - data?: T; - error?: unknown; -} - async function fetchCampaigns(): Promise { - const res = await fetchClient(`${API_URL}/campaigns`); - if (!res.ok) { - throw new Error(`Failed to fetch campaigns: ${res.status}`); - } - - const body = (await res.json()) as ApiResponse; - if (!body.success) { - throw new Error(body.message ?? 'Failed to fetch campaigns'); + const { data, error } = await apiClient.GET('/api/v1/campaigns', { + params: { query: { includeArchived: false } }, + }); + if (error) { + throw new Error((error as { message?: string }).message ?? 'Failed to fetch campaigns'); } - - return body.data ?? []; + const result = data as unknown as { data?: Campaign[] } | Campaign[] | null; + if (Array.isArray(result)) return result; + return result?.data ?? []; } async function postCampaign(payload: CampaignCreatePayload): Promise { - const res = await fetchClient(`${API_URL}/campaigns`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload), + const { data, error, response } = await apiClient.POST('/api/v1/campaigns', { + body: payload as never, }); - - if (![200, 201].includes(res.status)) { - const body = await res.json(); - throw new Error(body?.message ?? `Failed to create campaign: ${res.status}`); + if (error || !response.ok) { + throw new Error((error as { message?: string } | undefined)?.message ?? `Failed to create campaign`); } - - const body = (await res.json()) as ApiResponse; - if (!body.success) { - throw new Error(body.message ?? 'Failed to create campaign'); - } - - return body.data as Campaign; + const result = data as unknown as { data?: Campaign } | Campaign | null; + return (result && 'data' in result ? result.data : result) as Campaign; } async function patchCampaign(id: string, payload: CampaignUpdatePayload): Promise { - const res = await fetchClient(`${API_URL}/campaigns/${id}`, { - method: 'PATCH', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload), + const { data, error } = await apiClient.PATCH('/api/v1/campaigns/{id}', { + params: { path: { id } }, + body: payload as never, }); - - if (!res.ok) { - const body = await res.json(); - throw new Error(body?.message ?? `Failed to update campaign: ${res.status}`); + if (error) { + throw new Error((error as { message?: string }).message ?? `Failed to update campaign`); } - - const body = (await res.json()) as ApiResponse; - if (!body.success) { - throw new Error(body.message ?? 'Failed to update campaign'); - } - - return body.data as Campaign; + const result = data as unknown as { data?: Campaign } | Campaign | null; + return (result && 'data' in result ? result.data : result) as Campaign; } export function useCampaigns() { @@ -85,7 +57,7 @@ export function useCreateCampaign() { return trackJob( 'Create Campaign', `Creating campaign "${payload.name}"`, - () => postCampaign(payload) + () => postCampaign(payload), ); }, onSuccess: () => { diff --git a/app/frontend/src/hooks/useHealthStatus.ts b/app/frontend/src/hooks/useHealthStatus.ts index 537bcac1..2f6f22c2 100644 --- a/app/frontend/src/hooks/useHealthStatus.ts +++ b/app/frontend/src/hooks/useHealthStatus.ts @@ -1,33 +1,31 @@ 'use client'; import { useQuery } from '@tanstack/react-query'; -import { fetchClient } from '@/lib/mock-api/client'; +import { apiClient } from '@/lib/api-client'; import type { BackendHealthResponse, HealthState, HealthStatusResult, } from '@/types/health'; -const API_URL = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:4000'; - /** Polling interval: 30 seconds — reasonable for a health badge */ const POLL_INTERVAL_MS = 30_000; async function fetchHealth(): Promise { const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), 8_000); // 8 s timeout + const timeoutId = setTimeout(() => controller.abort(), 8_000); try { - const response = await fetchClient(`${API_URL}/health`, { + const { data, error } = await apiClient.GET('/api/v1/health', { signal: controller.signal, cache: 'no-store', - }); + } as Parameters[1]); - if (!response.ok) { - throw new Error(`Server responded with ${response.status}`); + if (error) { + throw new Error(`Server responded with an error`); } - return response.json() as Promise; + return data as BackendHealthResponse; } finally { clearTimeout(timeoutId); } @@ -45,10 +43,6 @@ function deriveState( return 'down'; } -/** - * Hook that polls the backend /health endpoint every 30 seconds. - * Returns a HealthStatusResult — state, raw data, error, and last-checked time. - */ export function useHealthStatus(): HealthStatusResult { const { data, error, isLoading, dataUpdatedAt } = useQuery< BackendHealthResponse, diff --git a/app/frontend/src/hooks/useOptimisticCampaignMutations.ts b/app/frontend/src/hooks/useOptimisticCampaignMutations.ts index 78932818..3ce5a66c 100644 --- a/app/frontend/src/hooks/useOptimisticCampaignMutations.ts +++ b/app/frontend/src/hooks/useOptimisticCampaignMutations.ts @@ -1,20 +1,11 @@ 'use client'; import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { fetchClient } from '@/lib/mock-api/client'; -import type { Campaign, CampaignStatus, CampaignUpdatePayload } from '@/types/campaign'; +import { apiClient } from '@/lib/api-client'; +import type { Campaign, CampaignStatus } from '@/types/campaign'; import { useToast } from '@/components/ToastProvider'; -const API_URL = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:4000'; - -interface ApiResponse { - success: boolean; - message?: string; - data?: T; - error?: unknown; -} - -export type CampaignAction = +export type CampaignAction = | { type: 'pause'; targetStatus: 'paused' } | { type: 'resume'; targetStatus: 'active' } | { type: 'archive'; targetStatus: 'archived' } @@ -30,26 +21,20 @@ const ACTION_CONFIG: Record { - const res = await fetchClient(`${API_URL}/campaigns/${id}`, { - method: 'PATCH', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ status } as CampaignUpdatePayload), + const { data, error } = await apiClient.PATCH('/api/v1/campaigns/{id}', { + params: { path: { id } }, + body: { status } as never, }); - if (!res.ok) { - const body = await res.json(); - throw new Error(body?.message ?? `Failed to update campaign: ${res.status}`); - } - - const body = (await res.json()) as ApiResponse; - if (!body.success) { - throw new Error(body.message ?? 'Failed to update campaign'); + if (error) { + throw new Error((error as { message?: string }).message ?? 'Failed to update campaign'); } - return body.data as Campaign; + const result = data as unknown as { data?: Campaign } | Campaign | null; + return (result && 'data' in result ? result.data : result) as Campaign; } interface MutationVariables { diff --git a/app/frontend/src/lib/api-client.ts b/app/frontend/src/lib/api-client.ts new file mode 100644 index 00000000..8a09a0f6 --- /dev/null +++ b/app/frontend/src/lib/api-client.ts @@ -0,0 +1,18 @@ +import createClient from 'openapi-fetch'; +import type { paths } from './generated/api'; +import { fetchClient } from './mock-api/client'; +import { apiUrl } from './env'; + +/** + * Typed API client for the ChainForge backend. + * + * - Types are generated from openapi.json via `pnpm generate:api`. + * - Requests are routed through fetchClient so mock interception + * (NEXT_PUBLIC_USE_MOCKS=true) works transparently. + * - Auth: the backend uses x-api-key headers. If a default key is needed, + * add `headers: { 'x-api-key': '...' }` to the createClient options. + */ +export const apiClient = createClient({ + baseUrl: apiUrl, + fetch: fetchClient as typeof fetch, +}); diff --git a/app/frontend/src/lib/generated/api.ts b/app/frontend/src/lib/generated/api.ts new file mode 100644 index 00000000..ed75f2f5 --- /dev/null +++ b/app/frontend/src/lib/generated/api.ts @@ -0,0 +1,6867 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +export interface paths { + "/api/v1": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Root endpoint (v1) + * @description Returns a welcome message and API information. Part of v1 API. + */ + get: operations["AppController_getHello_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/health": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Check system liveness and basic service metadata + * @description Returns process liveness details and service metadata. Part of v1 API. + */ + get: operations["HealthController_check_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/deprecated-test": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * @deprecated + * @description ⚠️ **DEPRECATED** + * + * **Reason:** This endpoint is for testing deprecation headers. + * + * **Deprecated since:** 2025-01-01 + * + * **Sunset date:** 2025-12-31 + * + * **Alternative:** /api/v1/health + * + * **Migration guide:** https://docs.chainforge.app/migration + */ + get: operations["AppController_deprecatedTest_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/health/live": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Liveness probe + * @description Returns process-level liveness information. Intended for orchestration liveness checks. + */ + get: operations["HealthController_liveness_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/health/ready": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Readiness probe + * @description Returns dependency readiness (database and optional Stellar RPC). Responds 503 when not ready. + */ + get: operations["HealthController_readiness_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/health/error": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Trigger an error for testing */ + get: operations["HealthController_triggerError_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/health/onchain": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * On-chain contract health probe (internal use) + * @description Performs a read-only contract call to verify connectivity to Soroban RPC and contract functionality. Requires authentication. + */ + get: operations["HealthController_onchainHealth_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/admin/ledger/backfill": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Trigger ledger backfill job + * @description Start a backfill job to process a range of ledgers and populate missing ledger entries. Idempotent - can be run repeatedly without duplicating data. + */ + post: operations["LedgerAdminController_triggerBackfill_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/admin/ledger/backfill/{jobId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get backfill job status + * @description Retrieve the current status of a backfill job. + */ + get: operations["LedgerAdminController_getBackfillStatus_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/admin/ledger/reconcile": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Trigger ledger reconciliation job + * @description Start a reconciliation job to compare on-chain data against stored records and detect discrepancies. + */ + post: operations["LedgerAdminController_triggerReconciliation_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/admin/ledger/reconcile/{jobId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get reconciliation job status + * @description Retrieve the current status and report of a reconciliation job. + */ + get: operations["LedgerAdminController_getReconciliationStatus_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/jobs/status": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get status of all background job queues + * @description Retrieves the count of waiting, active, completed, failed, and delayed jobs for all system queues. + */ + get: operations["JobsController_getStatus_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/jobs/health": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get overall health of background job queues + * @description Checks if any core queues are degraded (too many waiting or failed jobs). + */ + get: operations["JobsController_getHealth_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/metrics": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["PrometheusController_index_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/aid/campaigns": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Create a new campaign + * @description Initializes a new aid campaign with provided metadata. Requires appropriate permissions. + */ + post: operations["AidController_createCampaign_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/aid/campaigns/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Archive a campaign + * @description Soft-archives a campaign, making it invisible to standard listings. + */ + delete: operations["AidController_archiveCampaign_v1"]; + options?: never; + head?: never; + /** + * Update a campaign + * @description Modifies an existing campaign. Only provided fields will be updated. + */ + patch: operations["AidController_updateCampaign_v1"]; + trace?: never; + }; + "/api/v1/aid/claims/{id}/status": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** + * Transition a claim status + * @description Moves a claim from one status to another (e.g., pending -> approved). + */ + put: operations["AidController_transitionClaim_v1"]; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/aid/webhook": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Webhook for AI task notifications + * @description Receives notifications from the AI service when background tasks complete. + */ + post: operations["AidController_handleTaskWebhook_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification/claims/{id}/enqueue": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Enqueue claim verification job + * @description Add a claim to the verification queue for async processing. Returns immediately with job ID. + */ + post: operations["VerificationController_enqueueVerification_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification/metrics": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get verification queue metrics + * @description Retrieve current queue statistics including waiting, active, completed, and failed job counts + */ + get: operations["VerificationController_getMetrics_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification/start": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Start verification flow (OTP/email/phone) + * @description Start a verification session. Sends an OTP to the given email or phone. Rate-limited per identifier. + */ + post: operations["VerificationController_startVerification_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification/resend": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Resend verification code + * @description Resend OTP for an existing pending session. Limited resends per session. + */ + post: operations["VerificationController_resendVerification_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification/complete": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Complete verification with OTP + * @description Submit the OTP code to complete the verification. Attempts are rate-limited per session. + */ + post: operations["VerificationController_completeVerification_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Submit identity verification request (v1) + * @description Submit identity documents and information for verification. Supports document uploads and biometric data. Part of v1 API. + */ + post: operations["VerificationController_create_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification/claims/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get claim verification status + * @description Retrieve the current verification status and details of a claim + */ + get: operations["VerificationController_findClaim_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get verification status (v1) + * @description Retrieve the current status and details of a verification request. Part of v1 API. + */ + get: operations["VerificationController_findOne_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification/user/{userId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get user verification history (v1) + * @description Retrieve all verification requests for a specific user. Part of v1 API. + */ + get: operations["VerificationController_findByUser_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification/{id}/complete": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Mark verification as complete + * @description Updates the status of a verification request to complete and logs the action. + */ + post: operations["VerificationController_update_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification/{id}/notes": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List internal notes for a verification record + * @description Retrieves all internal notes for a specific verification. + */ + get: operations["VerificationController_getNotes_v1"]; + put?: never; + /** + * Add an internal note to a verification record + * @description Adds a secure internal note for staff review only. + */ + post: operations["VerificationController_addNote_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification-inbox": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get verification inbox + * @description Retrieve verification requests with filtering and pagination. Shows pending_review, approved, rejected, and needs_resubmission states. + */ + get: operations["VerificationInboxController_getInbox_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification-inbox/stats": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get verification inbox statistics + * @description Retrieve counts of verification requests by status for dashboard display. + */ + get: operations["VerificationInboxController_getStats_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification-inbox/{id}/approve": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Approve verification request + * @description Mark a verification request as approved and set next step messaging. + */ + post: operations["VerificationInboxController_approve_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification-inbox/{id}/reject": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Reject verification request + * @description Mark a verification request as rejected with reason and next step messaging. + */ + post: operations["VerificationInboxController_reject_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification-inbox/{id}/request-resubmission": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Request resubmission for verification + * @description Mark a verification request as needing resubmission with specific requirements. + */ + post: operations["VerificationInboxController_requestResubmission_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification-inbox/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get verification request details + * @description Retrieve detailed information about a specific verification request including review history. + */ + get: operations["VerificationInboxController_getDetails_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/verification-inbox/{id}/notes": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List internal notes for a verification request + * @description Retrieve all internal notes attached to a verification request. + */ + get: operations["VerificationInboxController_getInternalNotes_v1"]; + put?: never; + /** + * Add internal note to verification request + * @description Add an internal note visible only to reviewers. The action is recorded in the audit trail. + */ + post: operations["VerificationInboxController_addInternalNote_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/audit": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Query audit logs + * @description Retrieves a filtered list of audit logs based on entity, actor, or time range. + */ + get: operations["AuditController_getLogs_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/audit/export": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Export anonymized audit logs + * @description Exports anonymized audit logs as JSON or CSV with pagination and date-range filtering. Sensitive actor and entity IDs are replaced with deterministic SHA-256 hashes. + */ + get: operations["AuditController_exportLogs_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/notifications/outbox": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List stuck notification outbox records + * @description Returns all NotificationOutbox records in pending or enqueued status whose scheduledFor is more than 10 minutes in the past. + */ + get: operations["OutboxController_listStuck_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/notifications/outbox/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get a single notification outbox record + * @description Returns the NotificationOutbox record for the given id. + */ + get: operations["OutboxController_getOne_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/test-error/generic": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Trigger a generic Error */ + get: operations["TestErrorController_getGenericError_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/test-error/bad-request": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Trigger a BadRequestException */ + get: operations["TestErrorController_getBadRequest_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/test-error/internal-server-error": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Trigger an InternalServerErrorException */ + get: operations["TestErrorController_getInternalServerError_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/test-error/unauthorized": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Trigger an UnauthorizedException */ + get: operations["TestErrorController_getUnauthorized_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/test-error/forbidden": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Trigger a ForbiddenException */ + get: operations["TestErrorController_getForbidden_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/test-error/not-found": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Trigger a NotFoundException */ + get: operations["TestErrorController_getNotFound_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/test-error/validation-error": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Trigger a validation error via Post body */ + post: operations["TestErrorController_postValidationError_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/test-error/prisma-error-simulation": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Simulate a Prisma database error */ + get: operations["TestErrorController_getPrismaErrorSimulation_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/campaigns": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List all campaigns + * @description Retrieves campaigns. NGO operators only see their own organization's campaigns. + */ + get: operations["CampaignsController_list_v1"]; + put?: never; + /** Create a campaign */ + post: operations["CampaignsController_create_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/campaigns/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get campaign details + * @description Retrieves metadata and status for a specific campaign. + */ + get: operations["CampaignsController_get_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Update a campaign + * @description Modifies existing campaign properties. Only provided fields are updated. + */ + patch: operations["CampaignsController_update_v1"]; + trace?: never; + }; + "/api/v1/campaigns/{id}/archive": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Archive campaign (soft archive) + * @description Marks a campaign as archived. Archived campaigns are hidden from general listings. + */ + patch: operations["CampaignsController_archive_v1"]; + trace?: never; + }; + "/api/v1/campaigns/{id}/balance": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get campaign balance summary + * @description Returns the current locked, disbursed, and available budget for a campaign. Locked balance accounts for all active (non-cancelled, non-disbursed) claims. Cancelled claims release their locked amount back to available. + */ + get: operations["CampaignsController_getBalance_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/campaigns/{id}/budget-summary": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get campaign budget summary + * @description Returns the total, locked, disbursed, and available budget for a campaign. + */ + get: operations["CampaignsController_getBudgetSummary_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/campaigns/export": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Export campaigns as CSV + * @description Exports campaign summaries as CSV with support for date range, status, organization, and pagination filters. Excludes sensitive internal metadata and deleted records. + */ + get: operations["CampaignsController_exportCampaigns_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/claims": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List all claims + * @description Retrieves a list of all claims across all campaigns. + */ + get: operations["ClaimsController_findAll_v1"]; + put?: never; + /** + * Create a claim + * @description Initializes a new claim for a specific campaign. + */ + post: operations["ClaimsController_create_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/claims/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get claim details + * @description Retrieves the current details and status of a specific claim. + */ + get: operations["ClaimsController_findOne_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/claims/{id}/verify": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Verify a claim + * @description Marks a claim as verified. Requires operator or admin role. + */ + post: operations["ClaimsController_verify_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/claims/{id}/approve": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Approve a claim + * @description Approves a verified claim. Requires admin role. + */ + post: operations["ClaimsController_approve_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/claims/{id}/disburse": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Disburse funds for a claim + * @description Initiates on-chain disbursement for an approved claim. Requires admin role. + */ + post: operations["ClaimsController_disburse_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/claims/{id}/archive": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Archive a claim + * @description Soft-archives a claim, hiding it from general listings. + */ + patch: operations["ClaimsController_archive_v1"]; + trace?: never; + }; + "/api/v1/claims/{id}/receipt": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get claim receipt + * @description Generates a shareable receipt for the specified claim. + */ + get: operations["ClaimsController_getReceipt_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/claims/{id}/receipt/share": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Share claim receipt + * @description Generates and optionally sends the claim receipt via email or SMS. + */ + post: operations["ClaimsController_shareReceipt_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/claims/{id}/notes": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List internal notes for a claim + * @description Retrieves all internal notes for a specific claim. + */ + get: operations["ClaimsController_getNotes_v1"]; + put?: never; + /** + * Add an internal note to a claim + * @description Adds a secure internal note for staff review only. + */ + post: operations["ClaimsController_addNote_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/claims/{id}/cancel": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Cancel a claim + * @description Cancels an active claim (requested / verified / approved). Releases the locked budget back to the campaign and records a full audit trail. Disbursed claims cannot be cancelled. + */ + post: operations["ClaimsController_cancel_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/claims/{id}/reissue": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Cancel and reissue a claim + * @description Atomically cancels the original claim and creates a replacement. The replacement is linked to the original via `reissuedFromId`, preserving the full audit chain. Locked balances are transferred to the new claim — no double-counting occurs. Returns both the cancelled original and the new replacement. + */ + post: operations["ClaimsController_reissue_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/claims/{id}/reissue-history": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get reissue chain for a claim + * @description Returns the full lineage of a claim — the original and every replacement — ordered from oldest to newest. Pass any claim ID in the chain to retrieve the complete history. + */ + get: operations["ClaimsController_getReissueHistory_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/claims/export": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Export claims as CSV + * @description Exports claim records as CSV with support for date range, status, organization, token, and pagination filters. Excludes sensitive recipient data (recipientRef is encrypted and not exported). + */ + get: operations["ClaimsController_exportClaims_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/analytics/global-stats": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get global distribution statistics + * @description Returns aggregated totals and breakdowns by token and region for the dashboard. + */ + get: operations["AnalyticsController_getGlobalStats_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/analytics/map-data": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get map data points + * @description Returns a list of distribution points with coordinates and amounts for map visualization. + */ + get: operations["AnalyticsController_getMapData_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/analytics/map-anonymized": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get anonymized map data (GeoJSON) + * @description Returns distribution data in GeoJSON format with anonymized locations for privacy. + */ + get: operations["AnalyticsController_getMapAnonymizedData_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/onchain/aid-escrow/packages": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Create an aid package + * @description Creates a new aid package with specified recipient, amount, and expiration. Only authorized operators can create packages. + */ + post: operations["AidEscrowController_createAidPackage_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/onchain/aid-escrow/packages/batch": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Batch create aid packages + * @description Creates multiple aid packages for multiple recipients in a single transaction. More efficient than individual creation. + */ + post: operations["AidEscrowController_batchCreateAidPackages_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/onchain/aid-escrow/packages/{id}/claim": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Claim an aid package + * @description Claims an aid package as the recipient, transferring the funds to their wallet. Can only be claimed once. + */ + post: operations["AidEscrowController_claimAidPackage_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/onchain/aid-escrow/packages/{id}/disburse": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Disburse an aid package + * @description Disburses an aid package from the admin/operator, transferring funds to the recipient. Admin-only action. + */ + post: operations["AidEscrowController_disburseAidPackage_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/onchain/aid-escrow/packages/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get aid package details + * @description Retrieves the full details of an aid package including status, amount, and expiration. + */ + get: operations["AidEscrowController_getAidPackage_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/onchain/aid-escrow/stats": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get aid package statistics + * @description Retrieves aggregated statistics for aid packages by token, including total committed, claimed, and expired amounts. + */ + get: operations["AidEscrowController_getAidPackageStats_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/onchain/aid-escrow/transactions/{hash}/status": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get transaction status + * @description Polls Soroban RPC for the status of a transaction by its hash. Returns a normalized status: pending, succeeded, failed, or unknown. + */ + get: operations["AidEscrowController_getTransactionStatus_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/api-keys": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List API keys (masked previews only) */ + get: operations["ApiKeysController_list_v1"]; + put?: never; + /** + * Create an API key (returned once) + * @description Creates a new API key. The raw key is only returned at creation time; future listings show masked previews only. + */ + post: operations["ApiKeysController_create_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/api-keys/{id}/rotate": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Rotate an API key (revoke old, create new) */ + post: operations["ApiKeysController_rotate_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/api-keys/{id}/revoke": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Revoke an API key */ + post: operations["ApiKeysController_revoke_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/sessions": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get sessions by context + * @description Retrieve sessions filtered by context ID + */ + get: operations["SessionController_getSessions_v1"]; + put?: never; + /** + * Create a new session + * @description Create a new verification session with optional multi-step flow definition + */ + post: operations["SessionController_createSession_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/sessions/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get session by ID + * @description Retrieve session details including steps and current status + */ + get: operations["SessionController_getSession_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/sessions/{sessionId}/steps/{stepId}/submit": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Submit data to a session step + * @description Submit data to a specific step with idempotent handling using submission key + */ + post: operations["SessionController_submitToStep_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/sessions/{id}/resume": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Resume a session + * @description Resume an expired or paused session + */ + post: operations["SessionController_resumeSession_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/evidence/upload": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Upload evidence to queue + * @description Encrypts and stores a single evidence file locally for eventual upload. Accepts one file (max 10MB) in the "file" field. Allowed types: image/jpeg, image/png, image/gif, application/pdf, text/plain. + */ + post: operations["EvidenceController_upload_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/evidence/queue": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List evidence queue + * @description Retrieves all evidence items in the queue for the current user. + */ + get: operations["EvidenceController_getQueue_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/evidence/queue/{id}/retry": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Retry evidence upload + * @description Manually triggers a retry for a failed evidence upload. + */ + post: operations["EvidenceController_retry_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/evidence/queue/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Remove from queue + * @description Removes an evidence item from the queue and deletes the local file. + */ + delete: operations["EvidenceController_remove_v1"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/evidence/upload-sessions": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Create a chunked upload session */ + post: operations["UploadSessionController_create_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/evidence/upload-sessions/{id}/chunks": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Upload a single chunk */ + post: operations["UploadSessionController_uploadChunk_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/evidence/upload-sessions/{id}/finalize": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Finalize session and assemble evidence file */ + post: operations["UploadSessionController_finalize_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/evidence/upload-sessions/{id}/status": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get received chunks (for resume) */ + get: operations["UploadSessionController_status_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/retention-policy": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List all retention policies + * @description Returns all configured retention policies, ordered by entity. + */ + get: operations["RetentionPolicyController_findAll_v1"]; + put?: never; + /** + * Create a retention policy + * @description Defines a retention window and purge strategy for a specific entity type. + */ + post: operations["RetentionPolicyController_create_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/retention-policy/entities": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List supported entity names + * @description Returns the list of entity types that support retention policies. + */ + get: operations["RetentionPolicyController_getSupportedEntities_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/retention-policy/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get a single retention policy */ + get: operations["RetentionPolicyController_findOne_v1"]; + /** + * Update a retention policy + * @description Partially update a retention policy. Changes take effect on the next purge run. + */ + put: operations["RetentionPolicyController_update_v1"]; + post?: never; + /** + * Delete a retention policy + * @description Removes a retention policy. The entity will no longer be purged automatically. + */ + delete: operations["RetentionPolicyController_remove_v1"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/retention-policy/purge": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Trigger a purge run + * @description Manually trigger a retention purge for all enabled policies. Each purge produces an audit event recording the number of records affected. + */ + post: operations["RetentionPolicyController_executePurge_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/retention-policy/seed": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Seed default retention policies + * @description Creates default retention policies for all supported entities if they do not already exist. + */ + post: operations["RetentionPolicyController_seedDefaults_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/orgs/{id}/invites": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["InvitesController_listInvites_v1"]; + put?: never; + post: operations["InvitesController_createInvite_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/invites/{id}/accept": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations["InvitesController_acceptInvite_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/invites/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete: operations["InvitesController_revokeInvite_v1"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/admin/search": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["AdminSearchController_search_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/entity-linking/link": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Link extracted entity to canonical registry + * @description Create a link between an extracted entity and a canonical registry record with confidence scoring + */ + post: operations["EntityLinkingController_linkEntity_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/entity-linking/links": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Query entity links + * @description Search and filter entity links by various criteria + */ + get: operations["EntityLinkingController_queryLinks_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/entity-linking/campaign/{campaignId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get entity links by campaign + * @description Retrieve all entity links associated with a specific campaign + */ + get: operations["EntityLinkingController_getLinksByCampaign_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/entity-linking/claim/{claimId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get entity links by claim + * @description Retrieve all entity links associated with a specific claim + */ + get: operations["EntityLinkingController_getLinksByClaim_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/entity-linking/verification/{verificationId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get entity links by verification + * @description Retrieve all entity links associated with a specific verification + */ + get: operations["EntityLinkingController_getLinksByVerification_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/entity-linking/review/{linkId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Review and update entity link + * @description Manually review and curate an entity link + */ + patch: operations["EntityLinkingController_reviewLink_v1"]; + trace?: never; + }; + "/api/v1/entity-linking/registry/search": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Search canonical registry + * @description Search for potential matches in the canonical registry + */ + get: operations["EntityLinkingController_searchRegistry_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/deployment-metadata": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List all deployment metadata (admin only) + * @description Returns all contract deployment metadata records, ordered by deployment date (newest first). + */ + get: operations["DeploymentMetadataController_findAll_v1"]; + put?: never; + /** + * Create deployment metadata (admin only) + * @description Creates a new contract deployment metadata record. Used to record contract deployments with their network, address, and provenance. + */ + post: operations["DeploymentMetadataController_create_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/deployment-metadata/by-network/{network}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get deployment metadata by network (admin only) + * @description Returns all contract deployments for a specific network (e.g., testnet, mainnet). + */ + get: operations["DeploymentMetadataController_findByNetwork_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/deployment-metadata/by-contract/{network}/{contractName}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get deployment metadata by network and contract name (admin only) + * @description Returns the latest deployment metadata for a specific contract on a specific network. + */ + get: operations["DeploymentMetadataController_findByNetworkAndContractName_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/deployment-metadata/by-contract-id/{contractId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get deployment metadata by contract ID (admin only) + * @description Returns deployment metadata for a specific contract ID (address). + */ + get: operations["DeploymentMetadataController_findByContractId_v1"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/deployment-metadata/{id}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** + * Update deployment metadata (admin only) + * @description Updates an existing deployment metadata record. + */ + put: operations["DeploymentMetadataController_update_v1"]; + post?: never; + /** + * Delete deployment metadata (admin only) + * @description Deletes a deployment metadata record. + */ + delete: operations["DeploymentMetadataController_delete_v1"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/admin/sandbox/seed/tenant": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations["SandboxController_seedTenant_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/admin/sandbox/seed/campaigns": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations["SandboxController_seedCampaigns_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/admin/sandbox/seed/claims": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations["SandboxController_seedClaims_v1"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/v1/admin/sandbox/seed": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post: operations["SandboxController_seedAll_v1"]; + delete: operations["SandboxController_resetSeed_v1"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; +} +export type webhooks = Record; +export interface components { + schemas: { + AiTaskWebhookDto: { + /** + * @description The ID of the task + * @example task-123-abc + */ + taskId: string; + /** + * @description Unique delivery ID to prevent duplicate processing + * @example del_12345abcde + */ + deliveryId: string; + /** + * @description Timestamp of the event generation for state ordering + * @example 2024-03-24T10:30:00Z + */ + timestamp: string; + /** + * @description Status of the task + * @example completed + * @enum {string} + */ + status: "pending" | "processing" | "completed" | "failed"; + /** + * @description Result of the task execution + * @example { + * "prediction": "approved", + * "confidence": 0.95 + * } + */ + result?: Record; + /** + * @description Error message if task failed + * @example Image processing failed: invalid format + */ + error?: string; + /** + * @description Type of the task + * @example image_analysis + */ + taskType?: string; + /** + * @description Timestamp when the task completed + * @example 2024-03-24T10:30:00Z + */ + completedAt?: string; + }; + StartVerificationDto: { + /** + * @description Verification channel: email or phone + * @example email + * @enum {string} + */ + channel: "email" | "phone"; + /** + * @description Email address (required when channel is email) + * @example user@example.com + */ + email?: string; + /** + * @description Phone number (required when channel is phone) + * @example +15551234567 + */ + phone?: string; + }; + ResendVerificationDto: { + /** + * @description Verification session ID returned from start + * @example clv789xyz123 + */ + sessionId: string; + }; + CompleteVerificationDto: { + /** + * @description Unique identifier for the current verification session. + * @example ses_123abc456def + */ + sessionId: string; + /** + * @description OTP code received via email or phone + * @example 123456 + */ + code: string; + }; + CreateVerificationDto: { + /** + * @description User submitting the verification + * @example clu456def789 + */ + userId: string; + /** + * @description Document type being submitted + * @example NATIONAL_ID + */ + documentType: string; + /** + * Format: date-time + * @description Timestamp when the verification request was submitted. + * @example 2025-01-23T11:00:00.000Z + */ + submittedAt?: string; + }; + CreateInternalNoteDto: { + /** + * @description The content of the internal note. + * @example Investigation shows that the recipient has provided valid evidence. + */ + content: string; + /** + * @description Optional category for the note. + * @example investigation + */ + category?: string; + }; + InternalNoteResponseDto: { + /** @example clv789xyz123 */ + id: string; + /** @example claim */ + entityType: string; + /** @example clv789xyz123 */ + entityId: string; + /** @example Investigation notes... */ + content: string; + /** @example clv789xyz123 */ + authorId: string; + /** @example investigation */ + category?: Record | null; + /** + * Format: date-time + * @example 2025-01-23T11:00:00.000Z + */ + createdAt: string; + /** + * Format: date-time + * @example 2025-01-23T11:00:00.000Z + */ + updatedAt: string; + }; + /** + * @description Current status of the campaign. + * @enum {string} + */ + CampaignStatus: "draft" | "active" | "paused" | "completed" | "archived"; + CreateCampaignDto: { + /** + * @description Campaign title/name. + * @example Winter Relief 2026 + */ + name: string; + /** + * @description Total budget allocated to the campaign. + * @example 25000.5 + */ + budget: number; + /** + * @description Arbitrary campaign metadata (e.g., region, location, target audience). + * @example { + * "region": "Lagos", + * "partner": "NGO-A", + * "notes": "Phase 1" + * } + */ + metadata?: { + [key: string]: unknown; + }; + /** + * @description Current status of the campaign. + * @example draft + */ + status?: components["schemas"]["CampaignStatus"]; + }; + UpdateCampaignDto: { + /** + * @description Updated campaign title/name. + * @example Winter Relief 2026 - Extended + */ + name?: string; + /** + * @description Updated campaign budget. + * @example 30000 + */ + budget?: number; + /** + * @description Updated campaign metadata. + * @example { + * "region": "Lagos", + * "partner": "NGO-B" + * } + */ + metadata?: { + [key: string]: unknown; + }; + /** + * @description Updated campaign status. + * @example active + */ + status?: components["schemas"]["CampaignStatus"]; + }; + CreateClaimDto: { + /** + * @description ID of the campaign this claim belongs to + * @example campaign-uuid + */ + campaignId: string; + /** + * @description Amount requested in the claim + * @example 100.5 + */ + amount: number; + /** + * @description Reference to the recipient + * @example recipient-123 + */ + recipientRef: string; + /** + * @description Stellar token address (asset issuer or contract ID) for the distribution + * @example GATEMHCCKCY67ZUCKTROYN24ZYT5GK4EQZ5LKG3FZTSZ3NYNEJBBENSN + */ + tokenAddress: string; + /** + * @description Reference or link to evidence supporting the claim (e.g., photo, document hash). + * @example evidence-456 + */ + evidenceRef?: string; + /** + * Format: date-time + * @description When the claim should automatically expire if it remains unprocessed. + * @example 2026-05-31T23:59:59.000Z + */ + expiresAt?: string; + }; + ClaimReceiptDto: { + /** + * @description Unique claim identifier + * @example claim-uuid-123 + */ + claimId: string; + /** + * @description Campaign/package ID + * @example campaign-uuid-456 + */ + packageId: string; + /** + * @description Current status of the claim + * @example disbursed + * @enum {string} + */ + status: "requested" | "verified" | "approved" | "disbursed" | "archived" | "cancelled"; + /** + * @description Token amount for the claim + * @example 100.5 + */ + amount: number; + /** + * @description ISO timestamp of claim creation + * @example 2024-01-15T10:30:00Z + */ + timestamp: string; + /** + * @description Stellar token address (optional) + * @example GATEMHCCKCY67ZUCKTROYN24ZYT5GK4EQZ5LKG3FZTSZ3NYNEJBBENSN + */ + tokenAddress?: string; + /** + * @description Recipient reference (optional) + * @example recipient-ref-789 + */ + recipientRef?: string; + }; + SendReceiptShareDto: { + /** + * @description Email address(es) to send receipt to + * @example [ + * "recipient@example.com" + * ] + */ + emailAddresses: unknown[][]; + /** + * @description Phone number(s) to send receipt to (SMS) + * @example [ + * "+1234567890" + * ] + */ + phoneNumbers: unknown[][]; + /** + * @description Channel for sharing + * @example email + * @enum {string} + */ + channel: "email" | "sms" | "inline"; + /** @description Custom message to include with receipt (optional) */ + message?: string; + }; + ClaimShareResponseDto: { + /** @description Base64-encoded receipt image or data */ + receiptData: string; + /** + * @description MIME type of the receipt data + * @example text/plain + */ + mimeType: string; + /** + * @description Filename for download + * @example claim-receipt-uuid.txt + */ + filename: string; + /** @description Text representation of receipt for sharing */ + text: string; + }; + CancelClaimDto: { + /** + * @description ID of the operator performing the cancellation. + * @example operator-uuid + */ + operatorId: string; + /** + * @description Human-readable reason for cancellation. + * @example Recipient relocated; package no longer applicable. + */ + reason?: string; + }; + ReissueClaimDto: { + /** + * @description ID of the operator performing the reissue. + * @example operator-uuid + */ + operatorId: string; + /** + * @description Override amount for the replacement package. Defaults to the original amount when omitted. + * @example 750 + */ + amount?: number; + /** + * @description Override recipient reference for the replacement package. + * @example recipient-ref-new + */ + recipientRef?: string; + /** + * @description Human-readable reason for the reissue. + * @example Corrected amount after field verification. + */ + reason?: string; + }; + BreakdownEntry: { + /** @example USDC */ + label: string; + /** @example 1500.5 */ + totalAmount: number; + /** @example 45 */ + count: number; + }; + TimeframeBucket: { + /** @example 2026-03-01 */ + date: string; + /** @example 500 */ + totalAmount: number; + /** @example 10 */ + count: number; + }; + GlobalStatsDto: { + /** @example 250000 */ + totalAidDisbursed: number; + /** @example 1250 */ + totalRecipients: number; + /** @example 12 */ + activeCampaigns: number; + byToken: components["schemas"]["BreakdownEntry"][]; + byRegion: components["schemas"]["BreakdownEntry"][]; + timeSeries: components["schemas"]["TimeframeBucket"][]; + /** @example 2026-03-30T10:00:00Z */ + computedAt: string; + }; + MapDataPoint: { + /** @example pkg-123 */ + id: string; + /** @example 6.5244 */ + lat: number; + /** @example 3.3792 */ + lng: number; + /** @example 100 */ + amount: number; + /** @example USDC */ + token: string; + /** @example delivered */ + status: string; + /** @example Lagos */ + region: string; + }; + MapDataDto: { + points: components["schemas"]["MapDataPoint"][]; + /** @example 2026-03-30T10:00:00Z */ + computedAt: string; + }; + GeoJsonFeature: { + /** @example Feature */ + type: string; + /** + * @example { + * "type": "Point", + * "coordinates": [ + * 3.3792, + * 6.5244 + * ] + * } + */ + geometry: Record; + properties: Record; + }; + GeoJsonFeatureCollection: { + /** @example FeatureCollection */ + type: string; + features: components["schemas"]["GeoJsonFeature"][]; + /** @example 2026-03-30T10:00:00Z */ + computedAt: string; + }; + CreateAidPackageDto: { + /** + * @description Unique identifier for the package + * @example pkg_123456789 + */ + packageId: string; + /** + * @description Stellar address of the aid recipient + * @example GBUQWP3BOUZX34ULNQG23RQ6F4BFXWBTRSE53XSTE23JMCVOCJGXVSVZ + */ + recipientAddress: string; + /** + * @description Amount in stroops (i128 as string to preserve precision) + * @example 1000000000 + */ + amount: string; + /** + * @description Stellar token address + * @example GATEMHCCKCY67ZUCKTROYN24ZYT5GK4EQZ5LKG3FZTSZ3NYNEJBBENSN + */ + tokenAddress: string; + /** + * @description Unix timestamp when the package expires + * @example 1704067200 + */ + expiresAt: number; + /** + * @description Optional metadata as key-value pairs + * @example { + * "campaign_ref": "campaign-123", + * "region": "LATAM" + * } + */ + metadata?: Record; + }; + BatchCreateAidPackagesDto: { + /** + * @description Array of recipient Stellar addresses + * @example [ + * "GBUQWP3BOUZX34ULNQG23RQ6F4BFXWBTRSE53XSTE23JMCVOCJGXVSVZ", + * "GA5ZSEJYB37JRC5AVCIA5MOP4GZ5DA47EL5QRUVLYEK2OOABEXVR5CV7" + * ] + */ + recipientAddresses: string[]; + /** + * @description Array of amounts (in stroops, as strings) + * @example [ + * "1000000000", + * "500000000" + * ] + */ + amounts: string[]; + /** + * @description Stellar token address + * @example GATEMHCCKCY67ZUCKTROYN24ZYT5GK4EQZ5LKG3FZTSZ3NYNEJBBENSN + */ + tokenAddress: string; + /** + * @description Duration in seconds from now until expiration + * @example 2592000 + */ + expiresIn: number; + /** @description Optional metadata as key-value pairs */ + metadata?: Record; + }; + CreateApiKeyDto: { + /** + * @description Role associated with this API key. + * @example operator + * @enum {string} + */ + role: "admin" | "operator" | "client" | "ngo"; + /** + * @description Optional NGO scope for this key (required for NGO role). + * @example ngo_123 + */ + ngoId?: string; + /** + * @description Human-friendly description of the key purpose. + * @example Onchain worker (prod) + */ + description?: string; + }; + RevokeApiKeyDto: { + /** + * @description Optional reason for revocation. + * @example compromised + */ + reason?: string; + }; + SessionStepDefinitionDto: { + /** @description Name of the step */ + stepName: string; + /** @description Order of the step in the flow */ + stepOrder: number; + /** @description Maximum attempts allowed for this step */ + maxAttempts?: number; + /** @description Initial input data for the step */ + input?: Record; + }; + CreateSessionDto: { + /** + * @description Type of session to create + * @enum {string} + */ + type: "otp_verification" | "claim_verification" | "multi_step_verification"; + /** @description Context identifier (e.g., claim ID, user ID) */ + contextId?: string; + /** @description Additional metadata for the session */ + metadata?: Record; + /** @description Session expiration time */ + expiresAt?: string; + /** @description Steps to create for multi-step sessions */ + steps?: components["schemas"]["SessionStepDefinitionDto"][]; + }; + SessionStepResponseDto: { + id: string; + stepName: string; + stepOrder: number; + /** @enum {string} */ + status: "pending" | "in_progress" | "completed" | "failed" | "skipped"; + input?: Record; + output?: Record; + error?: string; + attempts: number; + maxAttempts: number; + /** Format: date-time */ + startedAt?: string; + /** Format: date-time */ + completedAt?: string; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt: string; + }; + SessionResponseDto: { + id: string; + /** @enum {string} */ + type: "otp_verification" | "claim_verification" | "multi_step_verification"; + /** @enum {string} */ + status: "pending" | "completed" | "expired" | "failed"; + contextId?: string; + metadata?: Record; + /** Format: date-time */ + expiresAt?: string; + /** Format: date-time */ + createdAt: string; + /** Format: date-time */ + updatedAt: string; + /** Format: date-time */ + completedAt?: string; + /** Format: date-time */ + failedAt?: string; + steps?: components["schemas"]["SessionStepResponseDto"][]; + currentStep?: components["schemas"]["SessionStepResponseDto"]; + nextStep?: components["schemas"]["SessionStepResponseDto"]; + }; + SubmitStepDto: { + /** @description Unique key for idempotent submission */ + submissionKey: string; + /** @description Step input data */ + payload: Record; + /** @description Optional step name to target specific step */ + stepName?: string; + }; + SubmissionResponseDto: { + id: string; + sessionId: string; + stepId?: string; + submissionKey: string; + payload: Record; + response?: Record; + /** Format: date-time */ + createdAt: string; + isIdempotent: boolean; + }; + CreateUploadSessionDto: Record; + UploadChunkDto: Record; + CreateRetentionPolicyDto: { + /** + * @description Entity type this policy applies to (e.g. AuditLog, VerificationSession, Session, Claim) + * @example AuditLog + */ + entity: string; + /** + * @description Number of days to retain records before purging + * @example 90 + */ + retentionDays: number; + /** + * @description Purge strategy: soft_delete, hard_delete, or anonymize + * @default soft_delete + * @enum {string} + */ + strategy: "soft_delete" | "hard_delete" | "anonymize"; + /** + * @description Whether the policy is active + * @default true + */ + enabled: boolean; + /** @description Human-readable description of the policy */ + description?: string; + }; + UpdateRetentionPolicyDto: { + /** + * @description Entity type this policy applies to (e.g. AuditLog, VerificationSession, Session, Claim) + * @example AuditLog + */ + entity?: string; + /** + * @description Number of days to retain records before purging + * @example 90 + */ + retentionDays?: number; + /** + * @description Purge strategy: soft_delete, hard_delete, or anonymize + * @default soft_delete + * @enum {string} + */ + strategy: "soft_delete" | "hard_delete" | "anonymize"; + /** + * @description Whether the policy is active + * @default true + */ + enabled: boolean; + /** @description Human-readable description of the policy */ + description?: string; + }; + CreateDeploymentMetadataDto: Record; + DeploymentMetadataResponseDto: Record; + UpdateDeploymentMetadataDto: Record; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export interface operations { + AppController_getHello_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Welcome message returned successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + }; + }; + HealthController_check_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Service is alive and basic metadata retrieved. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + }; + }; + AppController_deprecatedTest_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Success (Deprecated) */ + 200: { + headers: { + /** @description Deprecation date: 2025-01-01 */ + Deprecation?: string; + /** @description Sunset date: 2025-12-31 */ + Sunset?: string; + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HealthController_liveness_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Process is alive. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + }; + }; + HealthController_readiness_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Service is ready to serve traffic. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Service is not ready (one or more dependencies are down). */ + 503: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + }; + }; + HealthController_triggerError_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Test error triggered successfully. */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + HealthController_onchainHealth_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description On-chain health check completed successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description On-chain health check failed */ + 503: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + LedgerAdminController_triggerBackfill_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @description Starting ledger sequence number */ + startLedger: number; + /** @description Ending ledger sequence number */ + endLedger: number; + /** @description Optional campaign ID to filter */ + campaignId?: string; + /** @description Number of ledgers to process per batch (default: 100) */ + batchSize?: number; + }; + }; + }; + responses: { + /** @description Backfill job queued successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Invalid request parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized - valid JWT token required. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - admin role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + LedgerAdminController_getBackfillStatus_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Job ID returned from triggerBackfill */ + jobId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Backfill status retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized - valid JWT token required. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - admin role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + LedgerAdminController_triggerReconciliation_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** @description Starting ledger sequence number */ + startLedger: number; + /** @description Ending ledger sequence number */ + endLedger: number; + /** @description Optional campaign ID to filter */ + campaignId?: string; + /** @description Threshold percentage for amount mismatch (default: 5) */ + thresholdPercent?: number; + }; + }; + }; + responses: { + /** @description Reconciliation job queued successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Invalid request parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized - valid JWT token required. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - admin role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + LedgerAdminController_getReconciliationStatus_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Job ID returned from triggerReconciliation */ + jobId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Reconciliation status retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized - valid JWT token required. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - admin role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + JobsController_getStatus_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Queue statuses retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + }; + }; + JobsController_getHealth_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + PrometheusController_index_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AidController_createCampaign_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaign created successfully. */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid input parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AidController_archiveCampaign_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaign archived successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified campaign was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AidController_updateCampaign_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaign updated successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid update data. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified campaign was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AidController_transitionClaim_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Claim status transitioned successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid status transition requested. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified claim was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AidController_handleTaskWebhook_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["AiTaskWebhookDto"]; + }; + }; + responses: { + /** @description Webhook received successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid webhook payload. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationController_enqueueVerification_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Unique identifier of the claim to verify */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Verification job enqueued successfully. */ + 202: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Invalid claim ID or malformed request. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid or missing API key. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The requested claim could not be found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationController_getMetrics_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Queue metrics retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Invalid or missing API key. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationController_startVerification_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["StartVerificationDto"]; + }; + }; + responses: { + /** @description Verification started; code sent to channel. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Invalid input parameters or rate limit exceeded for this identifier. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationController_resendVerification_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ResendVerificationDto"]; + }; + }; + responses: { + /** @description New verification code sent successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Session is inactive, expired, or resend limit has been reached. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified verification session was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationController_completeVerification_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CompleteVerificationDto"]; + }; + }; + responses: { + /** @description Verification completed successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Invalid code, session expired, or too many failed attempts. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified verification session was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationController_create_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateVerificationDto"]; + "multipart/form-data": components["schemas"]["CreateVerificationDto"]; + }; + }; + responses: { + /** @description Verification request submitted successfully. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Invalid verification data or unsupported document format. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Missing or invalid authentication credentials. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationController_findClaim_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Unique identifier of the claim */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Claim verification status retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Unauthorized - valid JWT token required. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified claim could not be found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationController_findOne_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Unique identifier of the verification request */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Verification status retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Unauthorized - valid JWT token required. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified verification request was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationController_findByUser_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Unique identifier of the user */ + userId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User verification history retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Unauthorized - valid JWT token required. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationController_update_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Unique identifier of the verification request */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Verification status updated successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified verification request was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationController_getNotes_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Internal notes retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["InternalNoteResponseDto"][]; + }; + }; + /** @description Access denied - staff role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationController_addNote_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateInternalNoteDto"]; + }; + }; + responses: { + /** @description Internal note added successfully. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["InternalNoteResponseDto"]; + }; + }; + /** @description Access denied - staff role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationInboxController_getInbox_v1: { + parameters: { + query?: { + /** @description Filter by verification status */ + status?: "pending_review" | "approved" | "rejected" | "needs_resubmission"; + /** @description Page number (default: 1) */ + page?: number; + /** @description Items per page (default: 20) */ + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Verification inbox retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Unauthorized - valid JWT token required. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - operator or admin role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationInboxController_getStats_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Statistics retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Unauthorized - valid JWT token required. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - operator or admin role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationInboxController_approve_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Unique identifier of the verification request */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + nextStepMessage?: string; + internalNote?: string; + }; + }; + }; + responses: { + /** @description Verification approved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Invalid request or verification already processed. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified verification request was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationInboxController_reject_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Unique identifier of the verification request */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + rejectionReason: string; + nextStepMessage?: string; + internalNote?: string; + }; + }; + }; + responses: { + /** @description Verification rejected successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Invalid request or verification already processed. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified verification request was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationInboxController_requestResubmission_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Unique identifier of the verification request */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + rejectionReason: string; + nextStepMessage: string; + internalNote?: string; + }; + }; + }; + responses: { + /** @description Resubmission requested successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Invalid request or verification already processed. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified verification request was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationInboxController_getDetails_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Unique identifier of the verification request */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Verification details retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Unauthorized - valid JWT token required. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified verification request was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationInboxController_getInternalNotes_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Unique identifier of the verification request */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Internal notes retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified verification request was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + VerificationInboxController_addInternalNote_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Unique identifier of the verification request */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + content: string; + category?: string; + }; + }; + }; + responses: { + /** @description Internal note added successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description The specified verification request was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AuditController_getLogs_v1: { + parameters: { + query?: { + /** @description Items per page (default: 50, max: 200) */ + limit?: unknown; + /** @description Page number (default: 1) */ + page?: unknown; + /** @description ISO string */ + endTime?: unknown; + /** @description ISO string */ + startTime?: unknown; + action?: unknown; + actorId?: unknown; + entityId?: unknown; + entity?: unknown; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Audit logs retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Missing or invalid authentication credentials. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AuditController_exportLogs_v1: { + parameters: { + query?: { + /** @description Items per page (default: 50, max: 200) */ + limit?: unknown; + /** @description Page number (default: 1) */ + page?: unknown; + /** @description Filter by actor ID */ + actorId?: unknown; + /** @description Filter by action type */ + action?: unknown; + /** @description Filter by entity type */ + entity?: unknown; + /** @description End date (ISO string) */ + to?: unknown; + /** @description Start date (ISO string) */ + from?: unknown; + /** @description Export format (default: json) */ + format?: "json" | "csv"; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Audit logs exported successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Missing or invalid authentication credentials. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OutboxController_listStuck_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Stuck outbox records returned. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Missing or invalid API key. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Insufficient role (requires admin or operator). */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + OutboxController_getOne_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Outbox record returned. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Missing or invalid API key. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Insufficient role (requires admin or operator). */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Outbox record not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + TestErrorController_getGenericError_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Generic error triggered. */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + TestErrorController_getBadRequest_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Bad request triggered. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + TestErrorController_getInternalServerError_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Internal server error triggered. */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + TestErrorController_getUnauthorized_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Unauthorized error triggered. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + TestErrorController_getForbidden_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Forbidden error triggered. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + TestErrorController_getNotFound_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Not found error triggered. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + TestErrorController_postValidationError_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateVerificationDto"]; + }; + }; + responses: { + /** @description Validation passed. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Validation failed. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + TestErrorController_getPrismaErrorSimulation_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Database error simulated. */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_list_v1: { + parameters: { + query: { + includeArchived: boolean; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of campaigns retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Missing or invalid authentication credentials. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_create_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateCampaignDto"]; + }; + }; + responses: { + /** @description Campaign created successfully. */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid input parameters or malformed request body. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Missing or invalid authentication credentials. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - insufficient permissions for this operation. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_get_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaign details retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Missing or invalid authentication credentials. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified campaign was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_update_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateCampaignDto"]; + }; + }; + responses: { + /** @description Campaign updated successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid update data or malformed request body. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Missing or invalid authentication credentials. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - insufficient permissions. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified campaign was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_archive_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaign archived successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Missing or invalid authentication credentials. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - insufficient permissions. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified campaign was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_getBalance_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaign balance retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + campaignId?: string; + /** @description Total campaign budget. */ + budget?: number; + /** @description Amount locked by active claims. */ + lockedAmount?: number; + /** @description Amount already disbursed. */ + disbursedAmount?: number; + /** @description Remaining available budget. */ + availableBudget?: number; + }; + }; + }; + /** @description Access denied - operator role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Campaign not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + CampaignsController_getBudgetSummary_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaign budget summary retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + campaignId?: string; + budget?: number; + locked?: number; + disbursed?: number; + available?: number; + }; + }; + }; + }; + }; + CampaignsController_exportCampaigns_v1: { + parameters: { + query?: { + /** @description Items per page (default: 50, max: 200) */ + limit?: unknown; + /** @description Page number (default: 1) */ + page?: unknown; + /** @description NGO ID filter */ + ngoId?: unknown; + /** @description Organization ID filter */ + orgId?: unknown; + /** @description Campaign status filter */ + status?: unknown; + /** @description End date (ISO string) */ + to?: unknown; + /** @description Start date (ISO string) */ + from?: unknown; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Campaigns exported successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "text/csv": string; + }; + }; + /** @description Missing or invalid authentication credentials. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - operator or admin role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ClaimsController_findAll_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of all claims retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ClaimsController_create_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateClaimDto"]; + }; + }; + responses: { + /** @description Claim created successfully. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CreateClaimDto"]; + }; + }; + /** @description Invalid input parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified campaign was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ClaimsController_findOne_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Claim details retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified claim was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ClaimsController_verify_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Claim status transitioned to verified successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid status transition. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - insufficient permissions. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified claim was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ClaimsController_approve_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Claim approved successfully (verified → approved). */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid status transition. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - admin role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified claim was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ClaimsController_disburse_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description On-chain disbursement initiated or completed successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Invalid status transition or account state. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - admin role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified claim was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ClaimsController_archive_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Claim archived successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid status transition. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified claim was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ClaimsController_getReceipt_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Claim receipt generated successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ClaimReceiptDto"]; + }; + }; + /** @description The specified claim was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ClaimsController_shareReceipt_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["SendReceiptShareDto"]; + }; + }; + responses: { + /** @description Receipt generated and sharing initiated successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ClaimShareResponseDto"]; + }; + }; + /** @description Invalid share parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The specified claim was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ClaimsController_getNotes_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Internal notes retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["InternalNoteResponseDto"][]; + }; + }; + /** @description Access denied - staff role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ClaimsController_addNote_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateInternalNoteDto"]; + }; + }; + responses: { + /** @description Internal note added successfully. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["InternalNoteResponseDto"]; + }; + }; + /** @description Access denied - staff role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ClaimsController_cancel_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CancelClaimDto"]; + }; + }; + responses: { + /** @description Claim cancelled successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Claim is already cancelled or in a non-cancellable status. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - operator role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Claim not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ClaimsController_reissue_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["ReissueClaimDto"]; + }; + }; + responses: { + /** @description Original claim cancelled and replacement created. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @description The cancelled original claim. */ + original?: Record; + /** @description The newly created replacement claim. */ + replacement?: Record; + }; + }; + }; + /** @description Original claim is not in a cancellable status. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - operator role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Original claim not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ClaimsController_getReissueHistory_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Reissue chain retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": Record[]; + }; + }; + /** @description Access denied - operator role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Claim not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ClaimsController_exportClaims_v1: { + parameters: { + query?: { + /** @description Items per page (default: 50, max: 200) */ + limit?: unknown; + /** @description Page number (default: 1) */ + page?: unknown; + /** @description Token address filter */ + tokenAddress?: unknown; + /** @description Organization ID filter */ + orgId?: unknown; + /** @description Campaign ID filter */ + campaignId?: unknown; + /** @description Claim status filter */ + status?: unknown; + /** @description End date (ISO string) */ + to?: unknown; + /** @description Start date (ISO string) */ + from?: unknown; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Claims exported successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "text/csv": string; + }; + }; + /** @description Missing or invalid authentication credentials. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Access denied - operator or admin role required. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AnalyticsController_getGlobalStats_v1: { + parameters: { + query?: { + from?: string; + to?: string; + region?: string; + token?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Global statistics retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["GlobalStatsDto"]; + }; + }; + }; + }; + AnalyticsController_getMapData_v1: { + parameters: { + query?: { + region?: string; + token?: string; + status?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Map data points retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MapDataDto"]; + }; + }; + }; + }; + AnalyticsController_getMapAnonymizedData_v1: { + parameters: { + query?: { + region?: string; + token?: string; + status?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Anonymized GeoJSON data retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["GeoJsonFeatureCollection"]; + }; + }; + }; + }; + AidEscrowController_createAidPackage_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateAidPackageDto"]; + }; + }; + responses: { + /** @description Package created successfully. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Invalid input parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Blockchain transaction failed. */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AidEscrowController_batchCreateAidPackages_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["BatchCreateAidPackagesDto"]; + }; + }; + responses: { + /** @description Packages created successfully. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Invalid input or mismatched arrays. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Blockchain transaction failed. */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AidEscrowController_claimAidPackage_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Package claimed successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Package not found or not claimable. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Package does not exist. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Blockchain transaction failed. */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AidEscrowController_disburseAidPackage_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Package disbursed successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Package not found or not disbursable. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Package does not exist. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Blockchain transaction failed. */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AidEscrowController_getAidPackage_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Package details retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Package not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Failed to retrieve package. */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AidEscrowController_getAidPackageStats_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Statistics retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Invalid token address. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Failed to retrieve statistics. */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AidEscrowController_getTransactionStatus_v1: { + parameters: { + query?: never; + header?: never; + path: { + hash: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Transaction status retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Invalid transaction hash. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Transaction not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Failed to retrieve transaction status. */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ApiKeysController_list_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description API keys listed. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ApiKeysController_create_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateApiKeyDto"]; + }; + }; + responses: { + /** @description API key created. */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Invalid payload. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Missing or invalid credentials. */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Insufficient permissions. */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ApiKeysController_rotate_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description API key rotated. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Cannot rotate revoked key. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + ApiKeysController_revoke_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["RevokeApiKeyDto"]; + }; + }; + responses: { + /** @description API key revoked. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + SessionController_getSessions_v1: { + parameters: { + query?: { + /** @description Context ID to filter sessions */ + contextId?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Sessions retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SessionResponseDto"][]; + }; + }; + }; + }; + SessionController_createSession_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateSessionDto"]; + }; + }; + responses: { + /** @description Session created successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SessionResponseDto"]; + }; + }; + }; + }; + SessionController_getSession_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Session ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Session retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SessionResponseDto"]; + }; + }; + }; + }; + SessionController_submitToStep_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Session ID */ + sessionId: string; + /** @description Step ID */ + stepId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["SubmitStepDto"]; + }; + }; + responses: { + /** @description Step submission processed successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SubmissionResponseDto"]; + }; + }; + }; + }; + SessionController_resumeSession_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Session ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Session resumed successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SessionResponseDto"]; + }; + }; + }; + }; + EvidenceController_upload_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "multipart/form-data": { + /** Format: binary */ + file: string; + }; + }; + }; + responses: { + /** @description Evidence queued successfully. */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + EvidenceController_getQueue_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Queue retrieved successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + EvidenceController_retry_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Retry initiated. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + EvidenceController_remove_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Item removed successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UploadSessionController_create_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateUploadSessionDto"]; + }; + }; + responses: { + /** @description Session created. */ + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UploadSessionController_uploadChunk_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "multipart/form-data": components["schemas"]["UploadChunkDto"]; + }; + }; + responses: { + /** @description Chunk received. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UploadSessionController_finalize_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Evidence queued. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UploadSessionController_status_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Session status. */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + RetentionPolicyController_findAll_v1: { + parameters: { + query?: { + /** @description Filter by entity name */ + entity?: unknown; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + RetentionPolicyController_create_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateRetentionPolicyDto"]; + }; + }; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + RetentionPolicyController_getSupportedEntities_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + RetentionPolicyController_findOne_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Retention policy ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + RetentionPolicyController_update_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Retention policy ID */ + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateRetentionPolicyDto"]; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + RetentionPolicyController_remove_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Retention policy ID */ + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + RetentionPolicyController_executePurge_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + RetentionPolicyController_seedDefaults_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + InvitesController_listInvites_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + InvitesController_createInvite_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + InvitesController_acceptInvite_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + InvitesController_revokeInvite_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + AdminSearchController_search_v1: { + parameters: { + query: { + q: string; + entity: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + EntityLinkingController_linkEntity_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + EntityLinkingController_queryLinks_v1: { + parameters: { + query?: { + limit?: number; + page?: number; + isActive?: boolean; + minConfidence?: number; + entityType?: "organization" | "location" | "asset" | "project"; + sourceId?: unknown; + sourceType?: "campaign" | "claim" | "verification"; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + EntityLinkingController_getLinksByCampaign_v1: { + parameters: { + query?: { + entityType?: "organization" | "location" | "asset" | "project"; + }; + header?: never; + path: { + /** @description Campaign ID */ + campaignId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + EntityLinkingController_getLinksByClaim_v1: { + parameters: { + query?: { + entityType?: "organization" | "location" | "asset" | "project"; + }; + header?: never; + path: { + /** @description Claim ID */ + claimId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + EntityLinkingController_getLinksByVerification_v1: { + parameters: { + query?: { + entityType?: "organization" | "location" | "asset" | "project"; + }; + header?: never; + path: { + /** @description Verification ID */ + verificationId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + EntityLinkingController_reviewLink_v1: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Entity Link ID */ + linkId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + EntityLinkingController_searchRegistry_v1: { + parameters: { + query: { + entityType: "organization" | "location" | "asset" | "project"; + /** @description Search query */ + query: string; + limit?: number; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + DeploymentMetadataController_findAll_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Deployment metadata records. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DeploymentMetadataResponseDto"][]; + }; + }; + }; + }; + DeploymentMetadataController_create_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateDeploymentMetadataDto"]; + }; + }; + responses: { + /** @description Deployment metadata created successfully. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DeploymentMetadataResponseDto"]; + }; + }; + /** @description Invalid input parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Failed to create deployment metadata. */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + DeploymentMetadataController_findByNetwork_v1: { + parameters: { + query?: never; + header?: never; + path: { + network: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Deployment metadata for the specified network. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DeploymentMetadataResponseDto"][]; + }; + }; + /** @description No deployments found for this network. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + DeploymentMetadataController_findByNetworkAndContractName_v1: { + parameters: { + query?: never; + header?: never; + path: { + network: string; + contractName: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Deployment metadata for the specified contract. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DeploymentMetadataResponseDto"]; + }; + }; + /** @description Deployment metadata not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + DeploymentMetadataController_findByContractId_v1: { + parameters: { + query?: never; + header?: never; + path: { + contractId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Deployment metadata for the specified contract ID. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DeploymentMetadataResponseDto"]; + }; + }; + /** @description Deployment metadata not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + DeploymentMetadataController_update_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateDeploymentMetadataDto"]; + }; + }; + responses: { + /** @description Deployment metadata updated successfully. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DeploymentMetadataResponseDto"]; + }; + }; + /** @description Invalid input parameters. */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Deployment metadata not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + DeploymentMetadataController_delete_v1: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Deployment metadata not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + SandboxController_seedTenant_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + SandboxController_seedCampaigns_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + SandboxController_seedClaims_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + SandboxController_seedAll_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 201: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + SandboxController_resetSeed_v1: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; +} diff --git a/app/frontend/src/lib/verification-api.ts b/app/frontend/src/lib/verification-api.ts index b2293222..840a18d9 100644 --- a/app/frontend/src/lib/verification-api.ts +++ b/app/frontend/src/lib/verification-api.ts @@ -1,78 +1,55 @@ -/** - * API client for the AI evidence verification endpoint. - * - * Calls POST /api/v1/verification/start with a FormData payload - * and returns a typed VerificationResult on success. - * - * Error handling contract: - * - 4xx → throws VerificationApiError with the message from the response body - * - 5xx → throws VerificationApiError with a generic user-safe message - * - network failure → throws VerificationApiError with a generic user-safe message - */ - import type { VerificationResult } from '@/types/verification'; import { withRetry } from '@/lib/retry'; +import { apiClient } from '@/lib/api-client'; -const API_URL = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:4000'; - -/** - * Typed error thrown by startEvidenceVerification on all failure paths. - * Consumers can catch this and display `.message` directly in the UI. - */ export class VerificationApiError extends Error { - constructor(message: string) { - super(message); - this.name = 'VerificationApiError'; - } + constructor(message: string) { + super(message); + this.name = 'VerificationApiError'; + } } -/** - * Posts the validated, PII-safe evidence payload to the verification API. - * - * @param payload - FormData containing an optional `image` file and/or - * optional `text` string field. - * @returns Resolved VerificationResult containing `score` and `risk_level`. - * @throws VerificationApiError on any failure — message is safe to display - * directly in the UI. - */ export async function startEvidenceVerification( - payload: FormData, + payload: FormData, ): Promise { - let response: Response; + let data: VerificationResult | undefined; + let response: Response | undefined; + + try { + const result = await withRetry(() => + apiClient.POST('/api/v1/verification/start', { + // FormData is passed as-is; the cast bypasses the typed body schema + // since openapi-fetch serialises multipart differently per version. + body: payload as never, + }), + ); + data = result.data as VerificationResult | undefined; + response = result.response; + } catch { + throw new VerificationApiError( + 'Unable to reach the verification service. Please check your connection and try again.', + ); + } + + if (response && response.ok && data) { + return data; + } + if (response && response.status >= 400 && response.status < 500) { + let message = + 'The verification request was rejected. Please review your evidence and try again.'; try { - response = await withRetry(() => - fetch(`${API_URL}/api/v1/verification/start`, { - method: 'POST', - body: payload, - }), - ); + const body = (await response.json()) as { message?: string }; + if (typeof body.message === 'string' && body.message.trim().length > 0) { + message = body.message; + } } catch { - throw new VerificationApiError( - 'Unable to reach the verification service. Please check your connection and try again.', - ); + // JSON parsing failed — use the default message } + throw new VerificationApiError(message); + } - if (response.ok) { - const body = (await response.json()) as VerificationResult; - return body; - } - - if (response.status >= 400 && response.status < 500) { - let message = 'The verification request was rejected. Please review your evidence and try again.'; - try { - const body = (await response.json()) as { message?: string }; - if (typeof body.message === 'string' && body.message.trim().length > 0) { - message = body.message; - } - } catch { - // JSON parsing failed — use the default message - } - throw new VerificationApiError(message); - } - - // 5xx or unexpected status - throw new VerificationApiError( - 'The verification service is temporarily unavailable. Please try again in a moment.', - ); + throw new VerificationApiError( + 'The verification service is temporarily unavailable. Please try again in a moment.', + ); } diff --git a/app/frontend/src/lib/verification-inbox-api.ts b/app/frontend/src/lib/verification-inbox-api.ts index 2fd3f0d0..9c259138 100644 --- a/app/frontend/src/lib/verification-inbox-api.ts +++ b/app/frontend/src/lib/verification-inbox-api.ts @@ -1,5 +1,5 @@ -import { fetchClient } from '@/lib/mock-api/client'; import { withRetry } from '@/lib/retry'; +import { apiClient } from '@/lib/api-client'; import type { VerificationInboxResponse, VerificationInboxItem, @@ -8,55 +8,59 @@ import type { ReviewFilters, } from '@/types/verification-review'; -const API_URL = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:4000'; -const BASE = `${API_URL}/v1/verification-inbox`; - -function buildParams(filters: Partial): string { - const p = new URLSearchParams(); - if (filters.status) p.set('status', filters.status); - if (filters.page && filters.page > 1) p.set('page', String(filters.page)); - if (filters.dateFrom) p.set('dateFrom', filters.dateFrom); - if (filters.dateTo) p.set('dateTo', filters.dateTo); - const q = p.toString(); - return q ? `?${q}` : ''; -} - export async function fetchInbox( filters: Partial, ): Promise { - const res = await withRetry(() => fetchClient(`${BASE}${buildParams(filters)}`)); - if (!res.ok) throw new Error(`Failed to fetch inbox: ${res.status}`); - return res.json() as Promise; + const { data, error } = await withRetry(() => + apiClient.GET('/api/v1/verification-inbox', { + params: { + query: { + status: filters.status || undefined, + page: filters.page && filters.page > 1 ? filters.page : undefined, + dateFrom: filters.dateFrom || undefined, + dateTo: filters.dateTo || undefined, + }, + }, + }), + ); + if (error) throw new Error((error as { message?: string }).message ?? 'Failed to fetch inbox'); + return data as VerificationInboxResponse; } export async function fetchStats(): Promise { - const res = await withRetry(() => fetchClient(`${BASE}/stats`)); - if (!res.ok) throw new Error(`Failed to fetch stats: ${res.status}`); - return res.json() as Promise; + const { data, error } = await withRetry(() => + apiClient.GET('/api/v1/verification-inbox/stats'), + ); + if (error) throw new Error((error as { message?: string }).message ?? 'Failed to fetch stats'); + return data as VerificationStats; } export async function fetchDetails(id: string): Promise { - const res = await withRetry(() => fetchClient(`${BASE}/${id}`)); - if (!res.ok) throw new Error(`Failed to fetch verification: ${res.status}`); - return res.json() as Promise; + const { data, error } = await withRetry(() => + apiClient.GET('/api/v1/verification-inbox/{id}', { + params: { path: { id } }, + }), + ); + if (error) throw new Error((error as { message?: string }).message ?? 'Failed to fetch verification'); + return data as VerificationInboxItem; } export async function approveVerification( id: string, payload: { nextStepMessage?: string; internalNote?: string }, ): Promise { - const res = await withRetry(() => fetchClient(`${BASE}/${id}/approve`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload), - })); - if (!res.ok) { - const body = await res.json().catch(() => ({})); + const { data, error } = await withRetry(() => + apiClient.POST('/api/v1/verification-inbox/{id}/approve', { + params: { path: { id } }, + body: payload, + }), + ); + if (error) { throw new Error( - (body as { message?: string }).message ?? `Approve failed: ${res.status}`, + (error as { message?: string }).message ?? `Approve failed`, ); } - return res.json() as Promise; + return data as VerificationInboxItem; } export async function rejectVerification( @@ -67,18 +71,18 @@ export async function rejectVerification( internalNote?: string; }, ): Promise { - const res = await withRetry(() => fetchClient(`${BASE}/${id}/reject`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload), - })); - if (!res.ok) { - const body = await res.json().catch(() => ({})); + const { data, error } = await withRetry(() => + apiClient.POST('/api/v1/verification-inbox/{id}/reject', { + params: { path: { id } }, + body: payload, + }), + ); + if (error) { throw new Error( - (body as { message?: string }).message ?? `Reject failed: ${res.status}`, + (error as { message?: string }).message ?? `Reject failed`, ); } - return res.json() as Promise; + return data as VerificationInboxItem; } export async function requestResubmission( @@ -89,42 +93,44 @@ export async function requestResubmission( internalNote?: string; }, ): Promise { - const res = await withRetry(() => fetchClient(`${BASE}/${id}/request-resubmission`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload), - })); - if (!res.ok) { - const body = await res.json().catch(() => ({})); + const { data, error } = await withRetry(() => + apiClient.POST('/api/v1/verification-inbox/{id}/request-resubmission', { + params: { path: { id } }, + body: payload, + }), + ); + if (error) { throw new Error( - (body as { message?: string }).message ?? - `Resubmission request failed: ${res.status}`, + (error as { message?: string }).message ?? `Resubmission request failed`, ); } - return res.json() as Promise; + return data as VerificationInboxItem; } export async function fetchNotes(id: string): Promise { - const res = await withRetry(() => fetchClient(`${BASE}/${id}/notes`)); - if (!res.ok) throw new Error(`Failed to fetch notes: ${res.status}`); - return res.json() as Promise; + const { data, error } = await withRetry(() => + apiClient.GET('/api/v1/verification-inbox/{id}/notes', { + params: { path: { id } }, + }), + ); + if (error) throw new Error((error as { message?: string }).message ?? 'Failed to fetch notes'); + return (data ?? []) as InternalNote[]; } export async function addNote( id: string, payload: { content: string; category?: string }, ): Promise { - const res = await withRetry(() => fetchClient(`${BASE}/${id}/notes`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(payload), - })); - if (!res.ok) { - const body = await res.json().catch(() => ({})); + const { data, error } = await withRetry(() => + apiClient.POST('/api/v1/verification-inbox/{id}/notes', { + params: { path: { id } }, + body: payload, + }), + ); + if (error) { throw new Error( - (body as { message?: string }).message ?? - `Add note failed: ${res.status}`, + (error as { message?: string }).message ?? `Add note failed`, ); } - return res.json() as Promise; + return data as InternalNote; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dbee62b1..791aa066 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: dependencies: '@nestjs/swagger': specifier: ^11.2.6 - version: 11.2.6(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + version: 11.2.6(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) body-parser: specifier: ^2.2.2 version: 2.2.2 @@ -71,40 +71,40 @@ importers: dependencies: '@liaoliaots/nestjs-redis': specifier: ^10.0.0 - version: 10.0.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(ioredis@5.10.1) + version: 10.0.0(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(ioredis@5.10.1) '@nestjs/axios': specifier: ^4.0.1 - version: 4.0.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.13.6)(rxjs@7.8.2) + version: 4.0.1(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.13.6)(rxjs@7.8.2) '@nestjs/bull': specifier: ^11.0.4 - version: 11.0.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(bull@4.16.5) + version: 11.0.4(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(bull@4.16.5) '@nestjs/bullmq': specifier: ^11.0.4 - version: 11.0.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(bullmq@5.71.0) + version: 11.0.4(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(bullmq@5.79.0(redis@5.12.1(@opentelemetry/api@1.9.0))) '@nestjs/common': - specifier: ^11.0.1 - version: 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + specifier: ^11.1.27 + version: 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/config': specifier: ^4.0.2 - version: 4.0.3(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) + version: 4.0.3(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) '@nestjs/core': specifier: ^11.0.1 - version: 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/platform-express': specifier: ^11.0.1 - version: 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) + version: 11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) '@nestjs/schedule': specifier: ^5.0.1 - version: 5.0.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2)) + version: 5.0.1(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2)) '@nestjs/swagger': specifier: ^11.2.5 - version: 11.2.6(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + version: 11.2.6(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) '@nestjs/terminus': specifier: ^11.0.0 - version: 11.1.1(@nestjs/axios@4.0.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.13.6)(rxjs@7.8.2))(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@prisma/client@6.19.2(prisma@6.19.2(typescript@5.9.3))(typescript@5.9.3))(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.1(@nestjs/axios@4.0.1(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.13.6)(rxjs@7.8.2))(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@prisma/client@6.19.2(prisma@6.19.2(typescript@5.9.3))(typescript@5.9.3))(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/throttler': specifier: ^6.5.0 - version: 6.5.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2) + version: 6.5.0(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2) '@prisma/client': specifier: ^6.19.2 version: 6.19.2(prisma@6.19.2(typescript@5.9.3))(typescript@5.9.3) @@ -113,7 +113,7 @@ importers: version: 14.6.1 '@willsoto/nestjs-prometheus': specifier: ^6.0.2 - version: 6.0.2(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(prom-client@15.1.3) + version: 6.0.2(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(prom-client@15.1.3) axios: specifier: ^1.13.6 version: 1.13.6 @@ -121,8 +121,8 @@ importers: specifier: ^4.16.5 version: 4.16.5 bullmq: - specifier: ^5.67.0 - version: 5.71.0 + specifier: ^5.79.0 + version: 5.79.0(redis@5.12.1(@opentelemetry/api@1.9.0)) class-transformer: specifier: ^0.5.1 version: 0.5.1 @@ -177,7 +177,7 @@ importers: version: 11.0.9(chokidar@4.0.3)(typescript@5.9.3) '@nestjs/testing': specifier: ^11.0.1 - version: 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)) + version: 11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)) '@types/express': specifier: ^5.0.0 version: 5.0.6 @@ -301,6 +301,9 @@ importers: next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + openapi-fetch: + specifier: ^0.13.5 + version: 0.13.8 papaparse: specifier: ^5.5.3 version: 5.5.3 @@ -352,13 +355,16 @@ importers: version: 9.39.4(jiti@2.6.1) eslint-config-next: specifier: ^16.2.1 - version: 16.2.4(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + version: 16.2.4(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) jest: specifier: ^30.3.0 version: 30.3.0(@types/node@20.19.37)(ts-node@10.9.2(@swc/core@1.15.30(@swc/helpers@0.5.15))(@types/node@20.19.37)(typescript@5.9.3)) jest-environment-jsdom: specifier: ^30.0.0 version: 30.4.1 + openapi-typescript: + specifier: ^7.6.1 + version: 7.13.0(typescript@5.9.3) tailwindcss: specifier: ^4 version: 4.2.2 @@ -1675,9 +1681,6 @@ packages: '@ioredis/as-callback@3.0.0': resolution: {integrity: sha512-Kqv1rZ3WbgOrS+hgzJ5xG5WQuhvzzSTRYvNeyPMLOAM78MHSnuKI20JeJGbpuAt//LCuP0vsexZcorqW7kWhJg==} - '@ioredis/commands@1.5.0': - resolution: {integrity: sha512-eUgLqrMf8nJkZxT24JvVRrQya1vZkQh8BBeYNwGDqa5I0VUi8ACx7uFvAaLxintokpTenkK6DASvo/bvNbBGow==} - '@ioredis/commands@1.5.1': resolution: {integrity: sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==} @@ -1987,31 +1990,61 @@ packages: cpu: [arm64] os: [darwin] + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4': + resolution: {integrity: sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ==} + cpu: [arm64] + os: [darwin] + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3': resolution: {integrity: sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==} cpu: [x64] os: [darwin] + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4': + resolution: {integrity: sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w==} + cpu: [x64] + os: [darwin] + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3': resolution: {integrity: sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==} cpu: [arm64] os: [linux] + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4': + resolution: {integrity: sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw==} + cpu: [arm64] + os: [linux] + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3': resolution: {integrity: sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==} cpu: [arm] os: [linux] + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4': + resolution: {integrity: sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw==} + cpu: [arm] + os: [linux] + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3': resolution: {integrity: sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==} cpu: [x64] os: [linux] + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4': + resolution: {integrity: sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ==} + cpu: [x64] + os: [linux] + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': resolution: {integrity: sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==} cpu: [x64] os: [win32] + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4': + resolution: {integrity: sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ==} + cpu: [x64] + os: [win32] + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -2055,8 +2088,8 @@ packages: '@swc/core': optional: true - '@nestjs/common@11.1.17': - resolution: {integrity: sha512-hLODw5Abp8OQgA+mUO4tHou4krKgDtUcM9j5Ihxncst9XeyxYBTt2bwZm4e4EQr5E352S4Fyy6V3iFx9ggxKAg==} + '@nestjs/common@11.1.27': + resolution: {integrity: sha512-kEGSzqM2lWr4whh4Ubflw+oPZSEzxvRMu9WL+LveZploJWTjec5bBlCiRVlVzTPg2kIwBiLwWSvCCW7Wnin1gg==} peerDependencies: class-transformer: '>=0.4.1' class-validator: '>=0.13.2' @@ -3037,6 +3070,16 @@ packages: peerDependencies: '@redis/client': ^5.12.1 + '@redocly/ajv@8.11.2': + resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==} + + '@redocly/config@0.22.0': + resolution: {integrity: sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==} + + '@redocly/openapi-core@1.34.15': + resolution: {integrity: sha512-HAwCnNyKcs5XGQqms+9t7OdAPM/5TDstmhF+0i7tdCFato2QKuYIlyWETwkXd8c5zbltr1oB+6y9NTeQLr2d6Q==} + engines: {node: '>=18.17.0', npm: '>=9.5.0'} + '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} @@ -3085,6 +3128,7 @@ packages: '@stellar/stellar-base@14.1.0': resolution: {integrity: sha512-A8kFli6QGy22SRF45IjgPAJfUNGjnI+R7g4DF5NZYVsD1kGf7B4ITyc4OPclLV9tqNI4/lXxafGEw0JEUbHixw==} engines: {node: '>=20.0.0'} + deprecated: This package is now rolled into @stellar/stellar-sdk. Please use @stellar/stellar-sdk to continue receiving updates and support. '@stellar/stellar-sdk@14.6.1': resolution: {integrity: sha512-A1rQWDLdUasXkMXnYSuhgep+3ZZzyuXJKdt5/KAIc0gkmSp906HTvUpbT4pu+bVr41tu0+J4Ugz9J4BQAGGytg==} @@ -4255,8 +4299,14 @@ packages: resolution: {integrity: sha512-lDsx2BzkKe7gkCYiT5Acj02DpTwDznl/VNN7Psn7M3USPG7Vs/BaClZJJTAG+ufAR9++N1/NiUTdaFBWDIl5TQ==} engines: {node: '>=12'} - bullmq@5.71.0: - resolution: {integrity: sha512-aeNWh4drsafSKnAJeiNH/nZP/5O8ZdtdMbnOPZmpjXj7NZUP5YC901U3bIH41iZValm7d1i3c34ojv7q31m30w==} + bullmq@5.79.0: + resolution: {integrity: sha512-sg+kYGn7PIDI/AAkSWINPNz0vMp745YaBYMyo3AtcfXk5iCvjEPU+XMbU3yf7rSf1KsU+OfU+GH8FhxUa+WDNA==} + engines: {node: '>=12.22.0'} + peerDependencies: + redis: '>=5.0.0' + peerDependenciesMeta: + redis: + optional: true busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} @@ -4313,6 +4363,9 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + change-case@5.4.4: + resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} + char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} @@ -4454,6 +4507,9 @@ packages: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + colorette@1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -5373,8 +5429,8 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} - file-type@21.3.2: - resolution: {integrity: sha512-DLkUvGwep3poOV2wpzbHCOnSKGk1LzyXTv+aHFgN2VFl96wnp8YA9YjO2qPzg5PuL8q/SW9Pdi6WTkYOIh995w==} + file-type@21.3.4: + resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} engines: {node: '>=20'} fill-range@7.1.1: @@ -5776,6 +5832,10 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} + index-to-position@1.2.0: + resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==} + engines: {node: '>=18'} + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. @@ -5810,10 +5870,6 @@ packages: resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==} engines: {node: '>=12.22.0'} - ioredis@5.9.3: - resolution: {integrity: sha512-VI5tMCdeoxZWU5vjHWsiE/Su76JGhBvWF1MJnV9ZtGltHk9BmD48oDq8Tj8haZ85aceXZMxLNDQZRVo5QKNgXA==} - engines: {node: '>=12.22.0'} - ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -6448,6 +6504,10 @@ packages: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} + js-levenshtein@1.1.6: + resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} + engines: {node: '>=0.10.0'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -6976,6 +7036,10 @@ packages: minimatch@3.1.5: resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + minimatch@9.0.9: resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} @@ -7006,12 +7070,16 @@ packages: resolution: {integrity: sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==} hasBin: true - msgpackr@1.11.5: - resolution: {integrity: sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==} + msgpackr-extract@3.0.4: + resolution: {integrity: sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==} + hasBin: true msgpackr@1.11.9: resolution: {integrity: sha512-FkoAAyyA6HM8wL882EcEyFZ9s7hVADSwG9xrVx3dxxNQAtgADTrJoEWivID82Iv1zWDsv/OtbrrcZAzGzOMdNw==} + msgpackr@2.0.2: + resolution: {integrity: sha512-c5hYOXFbP79Slh6Dzd2wzk+jnV7mX1UxfMYtilnY1NmalXPqG8DGb5cYCMBrW4AsH3zekBBZd4QrKz9NhtvYLQ==} + multer@2.1.1: resolution: {integrity: sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==} engines: {node: '>= 10.16.0'} @@ -7334,6 +7402,18 @@ packages: zod: optional: true + openapi-fetch@0.13.8: + resolution: {integrity: sha512-yJ4QKRyNxE44baQ9mY5+r/kAzZ8yXMemtNAOFwOzRXJscdjSxxzWSNlyBAr+o5JjkUw9Lc3W7OIoca0cY3PYnQ==} + + openapi-typescript-helpers@0.0.15: + resolution: {integrity: sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw==} + + openapi-typescript@7.13.0: + resolution: {integrity: sha512-EFP392gcqXS7ntPvbhBzbF8TyBA+baIYEm791Hy5YkjDYKTnk/Tn5OQeKm5BIZvJihpp8Zzr4hzx0Irde1LNGQ==} + hasBin: true + peerDependencies: + typescript: ^5.x + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -7392,6 +7472,10 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-json@8.3.0: + resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} + engines: {node: '>=18'} + parse-png@2.1.0: resolution: {integrity: sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==} engines: {node: '>=10'} @@ -8438,6 +8522,10 @@ packages: resolution: {integrity: sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==} engines: {node: '>=14.18.0'} + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -8930,6 +9018,9 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + uri-js-replace@1.0.1: + resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -8981,10 +9072,6 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} - uuid@11.1.0: - resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} - hasBin: true - uuid@7.0.3: resolution: {integrity: sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==} deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). @@ -9250,6 +9337,9 @@ packages: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} + yaml-ast-parser@0.0.43: + resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==} + yaml@2.8.2: resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} engines: {node: '>= 14.6'} @@ -9402,7 +9492,7 @@ snapshots: '@babel/core@7.29.0': dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.1 '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) @@ -9413,7 +9503,7 @@ snapshots: '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -9473,7 +9563,7 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-plugin-utils': 7.28.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) lodash.debounce: 4.0.8 resolve: 1.22.11 transitivePeerDependencies: @@ -9501,7 +9591,7 @@ snapshots: dependencies: '@babel/core': 7.29.0 '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.29.7 '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color @@ -9549,9 +9639,9 @@ snapshots: '@babel/helper-wrap-function@7.28.6': dependencies: - '@babel/template': 7.28.6 + '@babel/template': 7.29.7 '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color @@ -9562,7 +9652,7 @@ snapshots: '@babel/highlight@7.25.9': dependencies: - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.29.7 chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.1.1 @@ -9992,7 +10082,7 @@ snapshots: '@babel/template@7.28.6': dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 '@babel/parser': 7.29.2 '@babel/types': 7.29.0 @@ -10004,13 +10094,13 @@ snapshots: '@babel/traverse@7.29.0': dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 '@babel/parser': 7.29.2 '@babel/template': 7.28.6 '@babel/types': 7.29.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -10022,7 +10112,7 @@ snapshots: '@babel/parser': 7.29.7 '@babel/template': 7.29.7 '@babel/types': 7.29.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -10118,7 +10208,7 @@ snapshots: '@eslint/config-array@0.21.2': dependencies: '@eslint/object-schema': 2.1.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -10134,7 +10224,7 @@ snapshots: '@eslint/eslintrc@3.3.5': dependencies: ajv: 6.14.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 @@ -10186,7 +10276,7 @@ snapshots: ci-info: 3.9.0 compression: 1.8.1 connect: 3.7.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) env-editor: 0.4.2 expo: 54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) expo-server: 1.0.5 @@ -10209,7 +10299,7 @@ snapshots: resolve: 1.22.11 resolve-from: 5.0.0 resolve.exports: 2.0.3 - semver: 7.7.4 + semver: 7.8.1 send: 0.19.2 slugify: 1.6.8 source-map-support: 0.5.21 @@ -10239,11 +10329,11 @@ snapshots: '@expo/plist': 0.4.8 '@expo/sdk-runtime-versions': 1.0.0 chalk: 4.1.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) getenv: 2.0.0 glob: 13.0.6 resolve-from: 5.0.0 - semver: 7.7.4 + semver: 7.8.1 slash: 3.0.0 slugify: 1.6.8 xcode: 3.0.1 @@ -10265,7 +10355,7 @@ snapshots: require-from-string: 2.0.2 resolve-from: 5.0.0 resolve-workspace-root: 2.0.1 - semver: 7.7.4 + semver: 7.8.1 slugify: 1.6.8 sucrase: 3.35.1 transitivePeerDependencies: @@ -10288,7 +10378,7 @@ snapshots: '@expo/env@2.0.11': dependencies: chalk: 4.1.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) dotenv: 16.4.7 dotenv-expand: 11.0.7 getenv: 2.0.0 @@ -10298,7 +10388,7 @@ snapshots: '@expo/env@2.1.1': dependencies: chalk: 4.1.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) getenv: 2.0.0 transitivePeerDependencies: - supports-color @@ -10310,14 +10400,14 @@ snapshots: '@expo/spawn-async': 1.7.2 arg: 5.0.2 chalk: 4.1.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) getenv: 2.0.0 glob: 13.0.6 ignore: 5.3.2 minimatch: 9.0.9 p-limit: 3.1.0 resolve-from: 5.0.0 - semver: 7.7.4 + semver: 7.8.1 transitivePeerDependencies: - supports-color @@ -10329,7 +10419,7 @@ snapshots: jimp-compact: 0.16.1 parse-png: 2.1.0 resolve-from: 5.0.0 - semver: 7.7.4 + semver: 7.8.1 '@expo/image-utils@0.8.13(typescript@5.9.3)': dependencies: @@ -10339,7 +10429,7 @@ snapshots: getenv: 2.0.0 jimp-compact: 0.16.1 parse-png: 2.1.0 - semver: 7.7.4 + semver: 7.8.1 transitivePeerDependencies: - supports-color - typescript @@ -10361,7 +10451,7 @@ snapshots: '@expo/spawn-async': 1.7.2 browserslist: 4.28.1 chalk: 4.1.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) dotenv: 16.4.7 dotenv-expand: 11.0.7 getenv: 2.0.0 @@ -10427,7 +10517,7 @@ snapshots: '@expo/image-utils': 0.8.12 '@expo/json-file': 10.0.12 '@react-native/normalize-colors': 0.81.5 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) expo: 54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) resolve-from: 5.0.0 semver: 7.8.1 @@ -10437,7 +10527,7 @@ snapshots: '@expo/require-utils@55.0.4(typescript@5.9.3)': dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 '@babel/core': 7.29.0 '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) optionalDependencies: @@ -10465,7 +10555,7 @@ snapshots: '@expo/xcpretty@4.4.1': dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 chalk: 4.1.2 js-yaml: 4.1.1 @@ -10756,8 +10846,6 @@ snapshots: '@ioredis/as-callback@3.0.0': {} - '@ioredis/commands@1.5.0': {} - '@ioredis/commands@1.5.1': {} '@isaacs/cliui@8.0.2': @@ -11373,10 +11461,10 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@liaoliaots/nestjs-redis@10.0.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(ioredis@5.10.1)': + '@liaoliaots/nestjs-redis@10.0.0(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(ioredis@5.10.1)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) ioredis: 5.10.1 tslib: 2.7.0 @@ -11394,21 +11482,39 @@ snapshots: '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': optional: true + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4': + optional: true + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3': optional: true + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4': + optional: true + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3': optional: true + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4': + optional: true + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3': optional: true + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4': + optional: true + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3': optional: true + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4': + optional: true + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': optional: true + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4': + optional: true + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.9.1 @@ -11416,32 +11522,32 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@nestjs/axios@4.0.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.13.6)(rxjs@7.8.2)': + '@nestjs/axios@4.0.1(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.13.6)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) axios: 1.13.6 rxjs: 7.8.2 - '@nestjs/bull-shared@11.0.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))': + '@nestjs/bull-shared@11.0.4(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) tslib: 2.8.1 - '@nestjs/bull@11.0.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(bull@4.16.5)': + '@nestjs/bull@11.0.4(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(bull@4.16.5)': dependencies: - '@nestjs/bull-shared': 11.0.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2)) - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/bull-shared': 11.0.4(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2)) + '@nestjs/common': 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) bull: 4.16.5 tslib: 2.8.1 - '@nestjs/bullmq@11.0.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(bullmq@5.71.0)': + '@nestjs/bullmq@11.0.4(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(bullmq@5.79.0(redis@5.12.1(@opentelemetry/api@1.9.0)))': dependencies: - '@nestjs/bull-shared': 11.0.4(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2)) - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) - bullmq: 5.71.0 + '@nestjs/bull-shared': 11.0.4(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2)) + '@nestjs/common': 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + bullmq: 5.79.0(redis@5.12.1(@opentelemetry/api@1.9.0)) tslib: 2.8.1 '@nestjs/cli@11.0.16(@swc/core@1.15.30(@swc/helpers@0.5.15))(@types/node@22.19.15)': @@ -11472,9 +11578,9 @@ snapshots: - uglify-js - webpack-cli - '@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - file-type: 21.3.2 + file-type: 21.3.4 iterare: 1.2.1 load-esm: 1.0.3 reflect-metadata: 0.2.2 @@ -11487,17 +11593,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@nestjs/config@4.0.3(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2)': + '@nestjs/config@4.0.3(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) dotenv: 17.2.3 dotenv-expand: 12.0.3 lodash: 4.17.23 rxjs: 7.8.2 - '@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nuxt/opencollective': 0.4.1 fast-safe-stringify: 2.1.1 iterare: 1.2.1 @@ -11507,20 +11613,20 @@ snapshots: tslib: 2.8.1 uid: 2.0.2 optionalDependencies: - '@nestjs/platform-express': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) + '@nestjs/platform-express': 11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) - '@nestjs/mapped-types@2.1.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': + '@nestjs/mapped-types@2.1.0(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) reflect-metadata: 0.2.2 optionalDependencies: class-transformer: 0.5.1 class-validator: 0.14.4 - '@nestjs/platform-express@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)': + '@nestjs/platform-express@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) cors: 2.8.6 express: 5.2.1 multer: 2.1.1 @@ -11529,10 +11635,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@nestjs/schedule@5.0.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))': + '@nestjs/schedule@5.0.1(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) cron: 3.5.0 '@nestjs/schematics@11.0.9(chokidar@4.0.3)(typescript@5.9.3)': @@ -11546,12 +11652,12 @@ snapshots: transitivePeerDependencies: - chokidar - '@nestjs/swagger@11.2.6(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': + '@nestjs/swagger@11.2.6(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': dependencies: '@microsoft/tsdoc': 0.16.0 - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/mapped-types': 2.1.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + '@nestjs/common': 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/mapped-types': 2.1.0(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) js-yaml: 4.1.1 lodash: 4.17.23 path-to-regexp: 8.3.0 @@ -11561,30 +11667,30 @@ snapshots: class-transformer: 0.5.1 class-validator: 0.14.4 - '@nestjs/terminus@11.1.1(@nestjs/axios@4.0.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.13.6)(rxjs@7.8.2))(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@prisma/client@6.19.2(prisma@6.19.2(typescript@5.9.3))(typescript@5.9.3))(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/terminus@11.1.1(@nestjs/axios@4.0.1(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.13.6)(rxjs@7.8.2))(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@prisma/client@6.19.2(prisma@6.19.2(typescript@5.9.3))(typescript@5.9.3))(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) boxen: 5.1.2 check-disk-space: 3.4.0 reflect-metadata: 0.2.2 rxjs: 7.8.2 optionalDependencies: - '@nestjs/axios': 4.0.1(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.13.6)(rxjs@7.8.2) + '@nestjs/axios': 4.0.1(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(axios@1.13.6)(rxjs@7.8.2) '@prisma/client': 6.19.2(prisma@6.19.2(typescript@5.9.3))(typescript@5.9.3) - '@nestjs/testing@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17))': + '@nestjs/testing@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17))': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) tslib: 2.8.1 optionalDependencies: - '@nestjs/platform-express': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) + '@nestjs/platform-express': 11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17) - '@nestjs/throttler@6.5.0(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)': + '@nestjs/throttler@6.5.0(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2))(reflect-metadata@0.2.2)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.17(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.17(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.17)(reflect-metadata@0.2.2)(rxjs@7.8.2) reflect-metadata: 0.2.2 '@next/env@16.2.1': {} @@ -12295,12 +12401,12 @@ snapshots: '@react-native/community-cli-plugin@0.81.5': dependencies: '@react-native/dev-middleware': 0.81.5 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) invariant: 2.2.4 metro: 0.83.5 metro-config: 0.83.5 metro-core: 0.83.5 - semver: 7.7.4 + semver: 7.8.1 transitivePeerDependencies: - bufferutil - supports-color @@ -12315,7 +12421,7 @@ snapshots: chrome-launcher: 0.15.2 chromium-edge-launcher: 0.2.0 connect: 3.7.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) invariant: 2.2.4 nullthrows: 1.1.1 open: 7.4.2 @@ -12424,6 +12530,29 @@ snapshots: dependencies: '@redis/client': 5.12.1(@opentelemetry/api@1.9.0) + '@redocly/ajv@8.11.2': + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js-replace: 1.0.1 + + '@redocly/config@0.22.0': {} + + '@redocly/openapi-core@1.34.15(supports-color@10.2.2)': + dependencies: + '@redocly/ajv': 8.11.2 + '@redocly/config': 0.22.0 + colorette: 1.4.0 + https-proxy-agent: 7.0.6(supports-color@10.2.2) + js-levenshtein: 1.1.6 + js-yaml: 4.1.1 + minimatch: 5.1.9 + pluralize: 8.0.0 + yaml-ast-parser: 0.0.43 + transitivePeerDependencies: + - supports-color + '@rtsao/scc@1.1.0': {} '@scarf/scarf@1.4.0': {} @@ -12680,7 +12809,7 @@ snapshots: '@tokenizer/inflate@0.4.1': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) token-types: 6.1.2 transitivePeerDependencies: - supports-color @@ -12924,7 +13053,7 @@ snapshots: '@typescript-eslint/types': 8.57.1 '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.57.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) eslint: 9.39.4(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: @@ -12934,7 +13063,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.57.1(typescript@5.9.3) '@typescript-eslint/types': 8.57.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -12953,7 +13082,7 @@ snapshots: '@typescript-eslint/types': 8.57.1 '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) '@typescript-eslint/utils': 8.57.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) eslint: 9.39.4(jiti@2.6.1) ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 @@ -12968,7 +13097,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.57.1(typescript@5.9.3) '@typescript-eslint/types': 8.57.1 '@typescript-eslint/visitor-keys': 8.57.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) minimatch: 10.2.4 semver: 7.8.1 tinyglobby: 0.2.15 @@ -13410,9 +13539,9 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 - '@willsoto/nestjs-prometheus@6.0.2(@nestjs/common@11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(prom-client@15.1.3)': + '@willsoto/nestjs-prometheus@6.0.2(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(prom-client@15.1.3)': dependencies: - '@nestjs/common': 11.1.17(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.27(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) prom-client: 15.1.3 '@xmldom/xmldom@0.8.11': {} @@ -13463,7 +13592,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -13824,7 +13953,7 @@ snapshots: babel-plugin-react-native-web: 0.21.2 babel-plugin-syntax-hermes-parser: 0.29.1 babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.29.0) - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) react-refresh: 0.14.2 resolve-from: 5.0.0 optionalDependencies: @@ -13892,7 +14021,7 @@ snapshots: dependencies: bytes: 3.1.2 content-type: 1.0.5 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 @@ -13984,15 +14113,16 @@ snapshots: transitivePeerDependencies: - supports-color - bullmq@5.71.0: + bullmq@5.79.0(redis@5.12.1(@opentelemetry/api@1.9.0)): dependencies: cron-parser: 4.9.0 - ioredis: 5.9.3 - msgpackr: 1.11.5 + ioredis: 5.10.1 + msgpackr: 2.0.2 node-abort-controller: 3.1.1 - semver: 7.7.4 + semver: 7.8.1 tslib: 2.8.1 - uuid: 11.1.0 + optionalDependencies: + redis: 5.12.1(@opentelemetry/api@1.9.0) transitivePeerDependencies: - supports-color @@ -14058,6 +14188,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + change-case@5.4.4: {} + char-regex@1.0.2: {} char-regex@2.0.2: {} @@ -14191,6 +14323,8 @@ snapshots: color-convert: 2.0.1 color-string: 1.9.1 + colorette@1.4.0: {} + colorette@2.0.20: {} combined-stream@1.0.8: @@ -14395,9 +14529,11 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.4.3: + debug@4.4.3(supports-color@10.2.2): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 10.2.2 decimal.js@10.6.0: {} @@ -14687,13 +14823,13 @@ snapshots: - supports-color - typescript - eslint-config-next@16.2.4(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3): + eslint-config-next@16.2.4(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3): dependencies: '@next/eslint-plugin-next': 16.2.4 eslint: 9.39.4(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.6.1)) eslint-plugin-react-hooks: 7.1.1(eslint@9.39.4(jiti@2.6.1)) @@ -14722,7 +14858,7 @@ snapshots: eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.6.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) eslint: 9.39.4(jiti@2.6.1) get-tsconfig: 4.13.6 is-bun-module: 2.0.0 @@ -14730,7 +14866,7 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)) transitivePeerDependencies: - supports-color @@ -14783,33 +14919,6 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.32.0(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.6.1)): - dependencies: - '@rtsao/scc': 1.1.0 - array-includes: 3.1.9 - array.prototype.findlastindex: 1.2.6 - array.prototype.flat: 1.3.3 - array.prototype.flatmap: 1.3.3 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 9.39.4(jiti@2.6.1) - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.6.1)))(eslint@9.39.4(jiti@2.6.1)) - hasown: 2.0.2 - is-core-module: 2.16.1 - is-glob: 4.0.3 - minimatch: 3.1.5 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.1 - semver: 6.3.1 - string.prototype.trimend: 1.0.9 - tsconfig-paths: 3.15.0 - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.4(jiti@2.6.1)): dependencies: aria-query: 5.3.2 @@ -14909,7 +15018,7 @@ snapshots: ajv: 6.14.0 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -15200,7 +15309,7 @@ snapshots: content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 @@ -15301,7 +15410,7 @@ snapshots: dependencies: flat-cache: 4.0.1 - file-type@21.3.2: + file-type@21.3.4: dependencies: '@tokenizer/inflate': 0.4.1 strtok3: 10.3.4 @@ -15330,7 +15439,7 @@ snapshots: finalhandler@2.1.1: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -15664,14 +15773,14 @@ snapshots: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -15680,14 +15789,14 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color - https-proxy-agent@7.0.6: + https-proxy-agent@7.0.6(supports-color@10.2.2): dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color @@ -15735,6 +15844,8 @@ snapshots: indent-string@4.0.0: {} + index-to-position@1.2.0: {} + inflight@1.0.6: dependencies: once: 1.4.0 @@ -15777,21 +15888,7 @@ snapshots: dependencies: '@ioredis/commands': 1.5.1 cluster-key-slot: 1.1.2 - debug: 4.4.3 - denque: 2.1.0 - lodash.defaults: 4.2.0 - lodash.isarguments: 3.1.0 - redis-errors: 1.2.0 - redis-parser: 3.0.0 - standard-as-callback: 2.1.0 - transitivePeerDependencies: - - supports-color - - ioredis@5.9.3: - dependencies: - '@ioredis/commands': 1.5.0 - cluster-key-slot: 1.1.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -15981,7 +16078,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -15990,7 +16087,7 @@ snapshots: istanbul-lib-source-maps@5.0.6: dependencies: '@jridgewell/trace-mapping': 0.3.31 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -16572,7 +16669,7 @@ snapshots: jest-message-util@29.7.0: dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 '@jest/types': 29.6.3 '@types/stack-utils': 2.0.3 chalk: 4.1.2 @@ -16596,7 +16693,7 @@ snapshots: jest-message-util@30.4.1: dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 '@jest/types': 30.4.1 '@types/stack-utils': 2.0.3 chalk: 4.1.2 @@ -16887,7 +16984,7 @@ snapshots: jest-util: 29.7.0 natural-compare: 1.4.0 pretty-format: 29.7.0 - semver: 7.7.4 + semver: 7.8.1 transitivePeerDependencies: - supports-color @@ -17133,6 +17230,8 @@ snapshots: joycon@3.1.1: {} + js-levenshtein@1.1.6: {} + js-tokens@4.0.0: {} js-yaml@3.14.2: @@ -17186,7 +17285,7 @@ snapshots: decimal.js: 10.6.0 html-encoding-sniffer: 4.0.0 http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 + https-proxy-agent: 7.0.6(supports-color@10.2.2) is-potential-custom-element-name: 1.0.1 nwsapi: 2.2.23 parse5: 7.3.0 @@ -17503,7 +17602,7 @@ snapshots: dependencies: exponential-backoff: 3.1.3 flow-enums-runtime: 0.0.6 - https-proxy-agent: 7.0.6 + https-proxy-agent: 7.0.6(supports-color@10.2.2) metro-core: 0.83.3 transitivePeerDependencies: - supports-color @@ -17512,7 +17611,7 @@ snapshots: dependencies: exponential-backoff: 3.1.3 flow-enums-runtime: 0.0.6 - https-proxy-agent: 7.0.6 + https-proxy-agent: 7.0.6(supports-color@10.2.2) metro-core: 0.83.5 transitivePeerDependencies: - supports-color @@ -17561,7 +17660,7 @@ snapshots: metro-file-map@0.83.3: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) fb-watchman: 2.0.2 flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 @@ -17575,7 +17674,7 @@ snapshots: metro-file-map@0.83.5: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) fb-watchman: 2.0.2 flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 @@ -17730,7 +17829,7 @@ snapshots: metro@0.83.3: dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 '@babel/core': 7.29.0 '@babel/generator': 7.29.1 '@babel/parser': 7.29.2 @@ -17741,7 +17840,7 @@ snapshots: chalk: 4.1.2 ci-info: 2.0.0 connect: 3.7.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) error-stack-parser: 2.1.4 flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 @@ -17777,7 +17876,7 @@ snapshots: metro@0.83.5: dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 '@babel/core': 7.29.0 '@babel/generator': 7.29.1 '@babel/parser': 7.29.2 @@ -17788,7 +17887,7 @@ snapshots: chalk: 4.1.2 ci-info: 2.0.0 connect: 3.7.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) error-stack-parser: 2.1.4 flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 @@ -17857,6 +17956,10 @@ snapshots: dependencies: brace-expansion: 1.1.12 + minimatch@5.1.9: + dependencies: + brace-expansion: 2.0.2 + minimatch@9.0.9: dependencies: brace-expansion: 2.0.2 @@ -17887,14 +17990,26 @@ snapshots: '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.3 optional: true - msgpackr@1.11.5: + msgpackr-extract@3.0.4: + dependencies: + node-gyp-build-optional-packages: 5.2.2 optionalDependencies: - msgpackr-extract: 3.0.3 + '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.4 + '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.4 + '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.4 + '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.4 + '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.4 + '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.4 + optional: true msgpackr@1.11.9: optionalDependencies: msgpackr-extract: 3.0.3 + msgpackr@2.0.2: + optionalDependencies: + msgpackr-extract: 3.0.4 + multer@2.1.1: dependencies: append-field: 1.0.0 @@ -18151,6 +18266,22 @@ snapshots: ws: 8.19.0 zod: 4.3.6 + openapi-fetch@0.13.8: + dependencies: + openapi-typescript-helpers: 0.0.15 + + openapi-typescript-helpers@0.0.15: {} + + openapi-typescript@7.13.0(typescript@5.9.3): + dependencies: + '@redocly/openapi-core': 1.34.15(supports-color@10.2.2) + ansi-colors: 4.1.3 + change-case: 5.4.4 + parse-json: 8.3.0 + supports-color: 10.2.2 + typescript: 5.9.3 + yargs-parser: 21.1.1 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -18230,11 +18361,17 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-json@8.3.0: + dependencies: + '@babel/code-frame': 7.29.7 + index-to-position: 1.2.0 + type-fest: 4.41.0 + parse-png@2.1.0: dependencies: pngjs: 3.4.0 @@ -18921,7 +19058,7 @@ snapshots: router@2.2.0: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 @@ -19023,7 +19160,7 @@ snapshots: send@1.2.1: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -19099,7 +19236,7 @@ snapshots: dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 - semver: 7.7.4 + semver: 7.8.1 optionalDependencies: '@img/sharp-darwin-arm64': 0.34.5 '@img/sharp-darwin-x64': 0.34.5 @@ -19402,7 +19539,7 @@ snapshots: dependencies: component-emitter: 1.3.1 cookiejar: 2.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) fast-safe-stringify: 2.1.1 form-data: 4.0.5 formidable: 3.5.4 @@ -19420,6 +19557,8 @@ snapshots: transitivePeerDependencies: - supports-color + supports-color@10.2.2: {} + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -19949,6 +20088,8 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + uri-js-replace@1.0.1: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -19999,8 +20140,6 @@ snapshots: utils-merge@1.0.1: {} - uuid@11.1.0: {} - uuid@7.0.3: {} uuid@8.3.2: {} @@ -20248,6 +20387,8 @@ snapshots: yallist@5.0.0: {} + yaml-ast-parser@0.0.43: {} + yaml@2.8.2: {} yargs-parser@21.1.1: {}